Android ACTION_IMAGE_CAPTURE Intención
Estamos intentando utilizar la aplicación de cámara nativa para permitir al usuario tomar una nueva fotografía. Funciona bien si omitimos EXTRA_OUTPUT extra
y devolvemos la pequeña imagen de mapa de bits. Sin embargo, si tenemos putExtra(EXTRA_OUTPUT,...)
la intención antes de iniciarlo, todo funciona hasta que intentas presionar el botón "Aceptar" en la aplicación de la cámara. El botón "Aceptar" simplemente no hace nada. La aplicación de la cámara permanece abierta y nada se bloquea. Podemos cancelarlo, pero el archivo nunca se escribe. ¿Qué tenemos que hacer exactamente para poder ACTION_IMAGE_CAPTURE
escribir la fotografía tomada en un archivo?
Editar: esto se hace a través de la MediaStore.ACTION_IMAGE_CAPTURE
intención, solo para que quede claro
Este es un error bien documentado en algunas versiones de Android. es decir, en las versiones de Android de la experiencia de Google, la captura de imágenes no funciona como se documenta. Lo que generalmente he usado es algo como esto en una clase de utilidades.
public boolean hasImageCaptureBug() {
// list of known devices that have the bug
ArrayList<String> devices = new ArrayList<String>();
devices.add("android-devphone1/dream_devphone/dream");
devices.add("generic/sdk/generic");
devices.add("vodafone/vfpioneer/sapphire");
devices.add("tmobile/kila/dream");
devices.add("verizon/voles/sholes");
devices.add("google_ion/google_ion/sapphire");
return devices.contains(android.os.Build.BRAND + "/" + android.os.Build.PRODUCT + "/"
+ android.os.Build.DEVICE);
}
luego, cuando inicio la captura de imágenes, creo una intención que busca el error.
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
if (hasImageCaptureBug()) {
i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File("/sdcard/tmp")));
} else {
i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
}
startActivityForResult(i, mRequestCode);
luego, en la actividad a la que vuelvo, hago cosas diferentes según el dispositivo.
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
switch (requestCode) {
case GlobalConstants.IMAGE_CAPTURE:
Uri u;
if (hasImageCaptureBug()) {
File fi = new File("/sdcard/tmp");
try {
u = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), fi.getAbsolutePath(), null, null));
if (!fi.delete()) {
Log.i("logMarker", "Failed to delete " + fi);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
} else {
u = intent.getData();
}
}
Esto le ahorra tener que escribir una nueva aplicación de cámara, pero este código tampoco es excelente. los grandes problemas son
nunca obtienes imágenes en tamaño completo de los dispositivos con el error. obtienes imágenes de 512 píxeles de ancho que se insertan en el proveedor de contenido de imágenes. en dispositivos sin el error, todo funciona como un documento, obtienes una imagen grande y normal.
Tienes que mantener la lista. tal como está escrito, es posible que los dispositivos se actualicen con una versión de Android (por ejemplo, las compilaciones de cyanogenmod ) que tenga el error solucionado. Si eso sucede, su código fallará. la solución es utilizar toda la huella digital del dispositivo.
Sé que esto ya se ha respondido antes, pero sé que mucha gente se equivoca con esto, así que agregaré un comentario.
Tuve exactamente el mismo problema en mi Nexus One. Esto era del archivo que no existía en el disco antes de que se iniciara la aplicación de la cámara. Por lo tanto, me aseguré de que el archivo existente antes de iniciar la aplicación de la cámara. Aquí hay un código de muestra que utilicé:
String storageState = Environment.getExternalStorageState();
if(storageState.equals(Environment.MEDIA_MOUNTED)) {
String path = Environment.getExternalStorageDirectory().getName() + File.separatorChar + "Android/data/" + MainActivity.this.getPackageName() + "/files/" + md5(upc) + ".jpg";
_photoFile = new File(path);
try {
if(_photoFile.exists() == false) {
_photoFile.getParentFile().mkdirs();
_photoFile.createNewFile();
}
} catch (IOException e) {
Log.e(TAG, "Could not create file.", e);
}
Log.i(TAG, path);
_fileUri = Uri.fromFile(_photoFile);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE );
intent.putExtra( MediaStore.EXTRA_OUTPUT, _fileUri);
startActivityForResult(intent, TAKE_PICTURE);
} else {
new AlertDialog.Builder(MainActivity.this)
.setMessage("External Storeage (SD Card) is required.\n\nCurrent state: " + storageState)
.setCancelable(true).create().show();
}
Primero creo un nombre de archivo único (algo) usando un hash MD5 y lo coloco en la carpeta apropiada. Luego verifico si existe (no debería, pero es una buena práctica comprobarlo de todos modos). Si no existe, obtengo el directorio principal (una carpeta) y creo la jerarquía de carpetas hasta él (por lo tanto, si las carpetas que conducen a la ubicación del archivo no existen, existirán después de esta línea. Luego, después de eso Creo el archivo. Una vez creado el archivo, obtengo el Uri y lo paso al intent y luego el botón Aceptar funciona como se esperaba y todo está dorado.
Ahora, cuando se presiona el botón Aceptar en la aplicación de la cámara, el archivo estará presente en la ubicación indicada. En este ejemplo sería /sdcard/Android/data/com.example.myapp/files/234asdioue23498ad.jpg
No es necesario copiar el archivo en "onActivityResult" como se publicó anteriormente.
He pasado por varias estrategias de captura de fotografías y siempre parece haber un caso, una plataforma o ciertos dispositivos, en el que algunas o todas las estrategias anteriores fallarán de manera inesperada. Pude encontrar una estrategia que utiliza el código de generación de URI a continuación que parece funcionar en la mayoría, si no en todos, los casos.
mPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new ContentValues());
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri);
startActivityForResult(intent,CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE_CONTENT_RESOLVER);
Para contribuir aún más a la discusión y ayudar a los recién llegados, he creado una aplicación de muestra/prueba que muestra varias estrategias diferentes para la implementación de la captura de fotografías. Definitivamente se alienta la contribución de otras implementaciones a la discusión.
https://github.com/deepwinter/AndroidCameraTester
Tuve el mismo problema donde el botón Aceptar en la aplicación de la cámara no hizo nada, ni en el emulador ni en el Nexus One.
El problema desapareció después de especificar un nombre de archivo seguro que no tenga espacios en blanco ni caracteres especiales. Además MediaStore.EXTRA_OUTPUT
, si especifica un archivo que reside en un directorio que aún no se ha creado, primero debe crearlo. La aplicación de cámara no hace mkdir por ti.