Nexus 7 y la cámara que no responde

Hace poco he  estado usando la cámara para trabajar con las fotos realizadas. El código es sencillo:

Uri uri = Uri.fromFile(mTempPictureFile)
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, TAKE_PICTURE_SUBACTIVITY);

El problema viene en donde colocar el fichero temporal.

Como la SDK de android tiene un método para tal propósito pues lo he usado.

File mTempPictureFile = File.createTempFile ("imagen", "jpg");

No se si en muchos dispositivos, pero esto inicialmente funciona aunque posteriormente he podido comprobar que coloca las imágenes en el raiz, y eso me parece muy poco conveniente.

Y decía en muchos porque no en todos. En la nexus 7 y en creo que en los samsumg III produce un curioso efecto, y eso que después de hacer la foto, no te permite aceptarla para usarla. En ambos casos, el software que controla la cámara te muestra una previsualización para aceptar o no la foto con un a X y un ✓ pero no permite confirmarla. Y para colmo, no deja unas trazas claras del problema.

La solución a este problema ha consistido en cambiar la ubicación del fichero, usando algo como:
File cacheDir = this.getExternalCacheDir();
cacheDir.mkdirs();
mTempPictureFile = new File(cacheDir,"waypointCapture.jpg");
mTempPictureFile.delete();
Uri uri = Uri.fromFile(mTempPictureFile);

Bueno, espero que os sea útil si os habéis encontrado con este problema.

Comartid! 🙂

ListActivity + ActionBarActivity

A muchos se nos ha ocurrido la feliz idea de añadir el ActionBar a nuestras aplicaciones que tienen algún Activity extendiendo de la clase ListActivity.

tulistaProSi nuestra aplicación además es compatible con versiones posteriores a android 2.1 debemos hacer que nuestro Activity extienda de ActionBarActivy y aquí comienzan la complicación: a los chicos de Google no se les ocurrió añadir un “ListActionBarActivity” o algo por el estilo.

Lo que es evidente es que no podemos extender de varias clases ya que java no soporta la multi-herencia así que nos toca buscar otro camino.

Se me ocurren dos soluciones así de pronto:

  1. Implementar nosotros mismos la gestión del ListView.
  2. Implementar una versión de ListActivity que extienda de ActionBarActivity y que luego nosotros usemos.

Vamos por el segundo caso y así, si tenemos varias activities que extiendan de ListActivity las solucionamos todas a la vez.

Como seguro que ya sabéis, desde hace algunas versiones Google incluye la posibilidad de descargar los fuentes de la SDK así que el primer paso es buscar el código fuente del ListView para buscar nuestra inspiración en él para crear nuestra clase ListActionBarActivity.

Hay algunas cosas que no nos sirven y tendremos que hacerlas ligeramente diferentes:

onContentChanged

public void onContentChanged() {
     super.onContentChanged();
     View emptyView = findViewById(com.android.internal.R.id.empty);
     mList = (ListView)findViewById(com.android.internal.R.id.list);
     [...]
}

Si usamos ese código tal cual dará error ya que la clase el contenido del paquete com.android.internal no está disponible para usarlo directamente. Lo que haremos será usar el paquete android.R para referirnos a él quedando el código como:

View emptyView = findViewById(android.R.id.empty);
mList = (ListView)findViewById(android.R.id.list);

Otro método que dará fallos es:
ensureList

private void ensureList() {
   if (mList != null) {
       return;
   }
   setContentView(com.android.internal.R.layout.list_content_simple);
}

Siempre deberíamos tener el contenido indicado no se me ocurre un activity sin su layout, así que de momento lanzaré una excepción a ver si averiguo cuando se puede dar esta situación y así resolverlo.

private void ensureList() {
   if (mList != null) {
     return;
   }
   //setContentView(com.android.internal.R.layout.list_content_simple);
   throw new RuntimeException("Esuring list but list is null");
}

Con estos cambio además de todos los cambios necesarios para añadir al ActionBar que ya vienen en la guía oficial debería funcionar en dispositivos con android v3.0 pero… no lo hará en dispositivos anteriores. ¿Por qué? Parece que la actual librería android.support.v7.app.ActionBarActivity ejecuta el método onContentChanged antes de que se hayan cargado los xml de nuestro layout, por lo que los métodos findViewById devolverán null. Aquí tenéis una entrada al respecto.

¿Cómo lo solucionamos? Pues tendremos que retrasar la inicialización de nuestras variables internas. Añadimos una variable de clase booleana para guardar cuando se puede ejecutar la búsqueda de nuestro ListView.

public void onContentChanged() {
  super.onContentChanged();
  if(mContentCharged){
     View emptyView = findViewById(android.R.id.empty);
     mList = (ListView) findViewById(android.R.id.list);
     [...]
  }
}

Y sobreescribimos el método setContentView que usamos (normalmente este):

@Override
public void setContentView(int layoutResID) {
  super.setContentView(layoutResID);
  mContentCharged = true;
  onContentChanged();
}

Creo que eso es todo!

Si te ha gustado ¡ayúdame a difundirlo! ¡Compártelo!! 😀