Sunday, April 10, 2016

Android, Chess y Layout - (Parte I)

Estoy intentando hacer una aplicación de ajedrez sencilla en Android. Como el diseño de pantallas en Android es en XML y es un poco complicado.... voy a hacer un proyecto nuevo de android vacío, desde cero, para tener únicamente las pantallas sin ningún tipo de comunicación con el backend, para poder tener la cáscara de la aplicación, sin complicarme con la lógica de negocio de la misma.

Con tal fin, hacemos este post, con el objetivo de mostrar una imágen de un diagrama de ajedez, y dos botones arriba.

Comencemos

Paso 00: Carga Inicial


El directorio de trabajo local es:

/Users/pabloin/Desktop/NoCuestaNada/Mob/GitHub-Android-Chess/ChessLab02



Paso 01: Areas de Activity


Luego, al activity default, le empezamos a editar nuestro prototipo:






Aline dos Linear Layout: Uno con orientación vertical, y otro otro, para la botonera con orientación horizontal. Le pinte el fondo, con distintos colores para poder visualizar a los espacio


   


















Lo cual se ve de la siguiente manera:






Paso 02: Agregar una Imagen al proyecto

Para agregar la imágenes, tenemos que crear los directorios:
“res/drawable-ldpi“,
“res/drawable-mdpi”
“res/drawable-hdpi“.

Android automáticamente tomara la imagen de acuerdo al dispositivo que ejecuta la aplicación ¿Con que criterio?

Se puede consultar:
https://developer.android.com/guide/practices/screens_support.html

Otro:
https://github.com/codepath/android_guides/wiki/Working-with-the-ImageView

La siguiente tabla ayudaría:
  • 36x36 for low-density (LDPI)
  • 48x48 for medium-density (MDPI)
  • 72x72 for high-density (HDPI)
  • 96x96 for extra high-density (XHDPI)
  • 180x180 for extra extra high-density (XXHDPI)
  • 192x192 for extra extra extra high-density (XXXHDPI)
Voy a copiar parte de una explicación de stack overflow sobre este tema, disculpen que esté en Ingles:

mdpi is the reference density -- that is, 1 px on an mdpi display is equal to 1 dip. The ratio for asset scaling is:
ldpi | mdpi | hdpi | xhdpi | xxhdpi | xxxhdpi 
0.75   1   | 1.5  | 2     | 3      | 4 

What this means is if you're doing a 48dip image and plan to support up to xhdpi resolution, you should start with a 96px image (144px if you want native assets for xxhdpi) and make the following images for the densities:
ldpi    | mdpi    | hdpi    | xhdpi     | xxhdpi    | xxxhdpi
36 x 36 | 48 x 48 | 72 x 72 | 96 x 96 | 144 x 144 | 192 x 192
And these should display at roughly the same size on any device, provided you've placed these in density-specific folders (e.g. drawable-xhdpi, drawable-hdpi, etc.)
For reference, the pixel densities for these are:
ldpi  | mdpi  | hdpi  | xhdpi  | xxhdpi  | xxxhdpi
120 | 160 | 240 | 320 | 480 | 640



Continuemos:

Las imágenes que queremos agregar son los diagramas de ajedrez, por ejemplo, uno:

Mate en dos de las blancas:



La imagen tiene dimensiones 392x 394

Vemos como quedó agregada al ejercicio:




Para agregar las imágenes, organizamos los siguientes directorios, donde el mismo contenido está copiado en los tres directorios:

“res/drawable-ldpi“,
“res/drawable-mdpi”
“res/drawable-hdpi“.




Luego, en el Android Studio, veamos como se relacionan:



Paso 03: Cambiamos la imagen dinámicamente ante un evento de click

Este paso es también bastante sencillo, vamos a agregar el mínimo código Java en el mainActivity para que funcione

Observar el "onClick"


   


Y el código Java simplemente:

O sea, definimos la ImageView y el método OnClick





Disculpen por la forma tan precaria de implementar la rotación de las 11 imágenes, obviamente esto no es viable de ninguna manera, pero servía para el ejemplo de este post, que es un poco descartable.... 

   
ImageView image;
int idx = 0;
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton)
findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action",
Snackbar.LENGTH_LONG)
.setAction("Action", null).show(); }
});

image = (ImageView) findViewById(R.id.chess_board_image);

}
public void nextMateEn2(View view) {

Log.d(TAG, "NETX - nextMateEn2 " + idx);
Log.d(TAG, "nextMateEn2 " + idx);
idx ++;
if (idx > 11) {
idx = 0; }

if (idx == 0) {
image.setImageResource(R.drawable.chess_mate2_00000); }

if (idx == 1) {
image.setImageResource(R.drawable.chess_mate2_00001); }

if (idx == 2) {
image.setImageResource(R.drawable.chess_mate2_00002); }

if (idx == 3) {
image.setImageResource(R.drawable.chess_mate2_00003); }

if (idx == 4) {
image.setImageResource(R.drawable.chess_mate2_00004); }

if (idx == 5) {
image.setImageResource(R.drawable.chess_mate2_00005); }

if (idx == 6) {
image.setImageResource(R.drawable.chess_mate2_00006); }

if (idx == 7) {
image.setImageResource(R.drawable.chess_mate2_00007); }

if (idx == 8) {
image.setImageResource(R.drawable.chess_mate2_00008); }

if (idx == 9) {
image.setImageResource(R.drawable.chess_mate2_00009); }

if (idx == 10) {
image.setImageResource(R.drawable.chess_mate2_00010); }

if (idx == 11) {
image.setImageResource(R.drawable.chess_mate2_00011); }

// Toast.makeText(this, "Boton Click", Toast.LENGTH_SHORT);

}


Estas son tres capturas del layout que responden al evento on click de los mates en 2, observemos como la imagen de la aplicación se modifica:

  


Con esto damos por cerrado los objetivos del post,

Fuentes en GitHub

Pueden tomar el ejercicio de GitHub en el siguiente branch

https://github.com/PabloEzequiel/Android/tree/ChessLab02





Labels: , ,

Wednesday, November 4, 2015

Crossfit Chess 1.0: Zero to App Android (Parte IV)

En el post anterior, la parte III de esta serie "Crossfit Chess 1.0: Zero to App Android" vimos como consumir servicios de la API REST con Gson y Volley, las librerías de Andorid

A la aplicación de ejemplo que intentamos hacer le pusimos de nombre Crossfit Chess porque pretende ser una App Sencilla en Android entrenadora de ajedrez.

En el paso de hoy, mostraremos las imágenes recuperadas del backend y las mostraremos en el activity





Comencemos

La API rest la habíamos construido con Node.js Heroku y la habíamos publicado en:




Debemos agregar una libreria al graddle

compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.4'
 Agregamos un nuevo botón y un ImageView:

Evento onCreate


La lista de productos, es la respuesta del Gson, o sea lo que recupera del backend:
Prestarle mas atención al Bloque debajo del rectángulo, donde se hace la invocación a Heroku

Este código se ejecuta en el onCreate
 El evento "callback" que procesa la invocación, y puebla la lista de productos que contiene las imágenes.
Este código se ejecuta en el onCreate:

Evento onClick




Luego, en el onClick del botón, como tenemos la lista de productos poblada, lo insertamos en el ImageView:


Veamos la aplicación funcionando en este punto:

  

  

Y después del último "Tap" vuelve al inicio:


Estas imágenes se podrían reemplazar por diagramas de distinta complejidad, donde el usuario podría resolver la solución. O bien ser la puerta de entrada a ejercicios de distintos niveles: los peones representando a los ejercicios mas sencillos y los reyes a los mas complejos.







Labels: , ,

Tuesday, November 3, 2015

Crossfit Chess 1.0: Zero to App Android (Parte III)

En esta serie de "Crossfit Chess 1.0: Zero to App Android" estamos haciendo una App Sencilla en Android que pretende ser un entrenador de ajedrez.

Para esto, tomará problemas desde un servidor, publicados con JSON.

En el post anterior vimos precisamente como consumimos un servicio Json con Gson, hoy seguiremos con la misma linea, pero invocando a mas servicios de la API, y finalmente mostrando en pantallas las imágenes recuperadas desde el servidor.

Comencemos

Paso 05 - Invocamos una API REST

La API rest la habíamos construido con Node.js y Heroku y la habíamos publicado en:






La cual se como:
Tenemos que darle el permiso a Internet en el AdnroidManifest:

<uses-permission android:name="android.permission.INTERNET"/>

Debemos agregar
compile 'com.mcxiaoke.volley:library:1.0.18'


Implementamos el GsonRequest, esta es una clase genérica, que puede ser siempre  igual 






O sea, asi está ok
   

public class GsonRequest extends Request {
private final Gson gson = new Gson();
private final Class clazz;
private final Map headers;
private final Response.Listener listener;

/**
* Make a GET request and return a parsed object from JSON.
*
* @param url URL of the request to make
* @param clazz Relevant class object, for Gson's reflection
* @param headers Map of request headers
*/
public GsonRequest(String url, Class clazz, Map headers,
Response.Listener listener, Response.ErrorListener errorListener) {
super(Method.GET, url, errorListener);
this.clazz = clazz;
this.headers = headers;
this.listener = listener;
}

@Override
public Map getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}

@Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}

@Override
protected Response parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(
response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(
gson.fromJson(json, clazz),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
}


Agregamos el código de invocación, es importante agregar también el "callback", o sea, la clase que manipulará las respuestas:

  

GsonRequestCallback gsonRequestCallback = new GsonRequestCallback();

GsonRequest gsonRequest = new GsonRequest<>(URL, Producto[].class, null, gsonRequestCallback, gsonRequestCallback);

Volley.newRequestQueue(this).add(gsonRequest);




Entonces la clase Callback es:
   
private class GsonRequestCallback implements
Response.Listener, Response.ErrorListener {

private String TAG_GSON = "GSON CallBack::" + GsonRequestCallback.class.getName();

/**
* Called when a response is received.
*
* @param response
*/
@Override
public void onResponse(Producto[] response) {
Log.d(TAG_GSON, "onResponse()" + response) ;

Toast.makeText(CrossfitChessActivity.this, "Productos: " + response.length, Toast.LENGTH_SHORT).show();

productos = Arrays.asList(response);

Log.d(TAG_GSON, "productos: " + productos);
}

/**
* Callback method that an error has been occurred with the
* provided error code and optional user-readable message.
*
* @param error
*/
@Override
public void onErrorResponse(VolleyError error) {

Log.d(TAG_GSON, "onErrorResponse()" + error);
Toast.makeText(CrossfitChessActivity.this, "ERROR", Toast.LENGTH_SHORT).show();
}
}





Nuevamente, la prueba de Junit, aunque estuvo cerca de funcionar.... no funcionó...

En la ejecución, observemos que muestra un Toast que dice que recuperó 6 productos desde el backend:



En el próximo post, veremos como esos 6 productos se muestran en la activity










Labels: , ,

Monday, November 2, 2015

Crossfit Chess 1.0: Zero to App Android (Parte II)

En el post anterior vimos los pasos básicos de la creación de la aplicación Crossfit Chess versión 1.0

Hoy vemos como agregar otros componentes básicos, concretamente agregaremos una ProgressBar y consumiremos un recurso Json (en el backend de heroku) con la libreria Gson

Comencemos

Paso 03 - Agregando un Progress Bar

   



Y en codigo java agregamos:
   

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);







Y en también la siguiente clase java encapsulamos:
   
/**
* Encapsula el prendido y apagado de la ProgressBar
*/
public static class MyProgressBar {

private static ProgressBar indicadorProgreso;
private static boolean isOff = true;

public static void switchProgressBar(AppCompatActivity activity) {
indicadorProgreso = MyProgressBar.getInstance(activity);
if (isOff) {
MyProgressBar.ON();
} else {
MyProgressBar.OFF();
}
}

private static ProgressBar getInstance(AppCompatActivity activity) {
if (indicadorProgreso == null) {
indicadorProgreso = (ProgressBar)activity.findViewById(R.id.indicador_progreso);
}

return indicadorProgreso;
}

private static void OFF() {
indicadorProgreso.setVisibility(View.GONE);
isOff = true;
}

private static void ON() {
indicadorProgreso.setVisibility(View.VISIBLE);
isOff = false;
}
}



Veamos como agregamos la progress bar:





Sobre el activity

Agregamos el código XML de la progress bar que mencionábamos más arriba.
Y la clase Java que hicimos para encapsular

El resultado:



De esa forma se ve la progress bar activa/inactiva


Paso 04: Parseamos un Json

Para parsear un Json, que es:






Agregamos las dependencias de GSON en el build.gradle

Una clase para la abstracción del objeto que vamos a recibir:

Quise agregar código para invocar al Gson desde los Junit pero no funciono... no lo repliquen, o háganlo mejor :)
 El resultado:
Pero desde el Main Activity anduvo ok:

O sea, recuperamos el Json del servidor

En el proximo post, tomaremos esas imágenes y las mostraremos en la aplicación.



Labels: , ,

Saturday, May 11, 2013

Amazon Developing A High-End 3D Smartphone

amazon logo
While Amazon has been quite successful with it’s Kindle e-readers and Kindle Fire tablets, it has been rumored since long that the company will foray into the smart phone segment as well. 
Now, according to a latest report, Amazon is working on not one, but two smart phones, one of which will be a high-end 3D smart phone, featuring a glassless 3D display. The smart phone will use a retina-tracking technology, using which the 3D image on the smartphone will refocus as per the movement of user’s eyes, allowing users to easily view content in 3D at all angles.
Using the same retina tracking technology, users will be able to navigate through content on the smart phone, just like we’ve seen on the Samsung Galaxy S4. 
Interestingly, the report says that the two smart phones are only a part of the larger hardware push by the company, which also plans to introduce an audio-only streaming device. Other than that, Amazon is also building a set top box for streaming movies and TV shows.
The report adds that Amazon plans to introduce the new devices in the coming months, but says that some or all these devices might also be dropped pertaining to issues related to the performance of these devices or other financial reasons. 
If Amazon does introduce it’s own smart phone, it will bring the company in a direct competition with the likes of Apple and Google.




Labels: , , ,