Android Camera.takePicture ha fallado

Como un poco de un ejercicio de aprendizaje, estoy escribiendo una aplicación de seguridad que, cuando ocurre un evento arbitrario, necesita encender la cámara, tomar una fotografía y apagar la cámara, sin preocuparse por el flash, el enfoque o la visualización de un avance. Seguí a lo largo de las demostraciones en línea e hizo una aplicación de trabajo que toma una foto, pero utiliza vistas previas y todo eso. Así que empecé a trabajar en conseguir que funcione sin una vista previa. De todos modos, sigo recibiendo 'takePicture falló' excepciones, y no tengo ninguna idea terrenal de por qué. Esperaba que alguien con más experiencia con la API de cámara pudiera echar un vistazo y señalarme en la dirección de una solución. A continuación se presentan mis archivos pertinentes. Estoy usando el último Android Studio y probando en el Galaxy S4.

[MainActivity.java]

package com.g5digital.cam2; import android.content.pm.PackageManager; import android.hardware.Camera; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.Toast; import java.io.IOException; public class MainActivity extends ActionBarActivity implements View.OnClickListener { private static final String TAG = "MainActivity"; private Button button; private int cameraId; private Camera camera; private CameraPreview camPreview; private LinearLayout container; private Camera.Parameters camParms; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); container = (LinearLayout)findViewById(R.id.container); button = (Button)findViewById(R.id.button); button.setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } @Override public void onClick(View view) { openCamera(); try { if (camera != null) { PhotoHandler ph = new PhotoHandler(this, camera); camera.takePicture(null, null, ph); // Commented until takePicture() works /*(new Handler()).postDelayed(new Runnable() { @Override public void run() { MainActivity.this.closeCamera(); } }, 1000);*/ } } catch (Exception e) { closeCamera(); Log.d(TAG, e.getMessage()); e.printStackTrace(); } } private void openCamera() { // do we have a camera? if (!getPackageManager() .hasSystemFeature(PackageManager.FEATURE_CAMERA)) { Toast.makeText(this, "No camera on this device", Toast.LENGTH_LONG) .show(); } else { closeCamera(); cameraId = findFrontFacingCameraId(); if (cameraId < 0) { Toast.makeText(this, "No front facing camera found.", Toast.LENGTH_LONG).show(); } else { camera = Camera.open(cameraId); try { setCamParms(); setCamPreview(); camera.startPreview(); } catch (Exception e) { closeCamera(); e.printStackTrace(); finish(); return; } } } } private void closeCamera() { if (camera != null) { camera.release(); camera = null; } } private int findFrontFacingCameraId() { int camera_id = -1; // Search for the front facing camera int numberOfCameras = Camera.getNumberOfCameras(); for (int i = 0; i < numberOfCameras; i++) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(i, info); if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { Log.d(TAG, "Camera found"); camera_id = i; break; } } return camera_id; } private void setCamParms() { if (camParms == null && camera != null) { camParms = camera.getParameters(); camParms.setFlashMode("Off"); } if (camera != null) { camera.setParameters(camParms); camera.setDisplayOrientation(90); } } private void setCamPreview() throws IOException { if (camPreview == null && camera != null) { camPreview = new CameraPreview(this, camera); } if (camera != null) { camera.setPreviewDisplay(camPreview.getHolder()); } } } 

[CameraPreview.java]

 package com.g5digital.cam2; import android.content.Context; import android.hardware.Camera; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import java.io.IOException; public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private Context context; private Camera camera; private SurfaceHolder holder; private static final String TAG = "CameraPreview"; public CameraPreview(Context c, Camera cam) { super(c); context = c; camera = cam; holder = getHolder(); holder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { try { camera.setPreviewDisplay(holder); camera.startPreview(); } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } catch (Exception e) { // Probably getting "called after release()" message e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (holder.getSurface() == null){ // preview surface does not exist return; } // stop preview before making changes try { camera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings try { camera.setPreviewDisplay(holder); camera.startPreview(); } catch (Exception e){ Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { // } } 

[PhotoHandler.java]

 package com.g5digital.cam2; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.hardware.Camera; import android.os.Environment; import android.util.Log; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.Date; public class PhotoHandler implements Camera.PictureCallback { private final Context context; private final Camera camera; public PhotoHandler(Context context, Camera c) { this.context = context; this.camera = c; } @Override public void onPictureTaken(byte[] bytes, Camera cam) { Log.i("PhotoHandler", "Picture taken!"); File pictureFileDir = getDir(); if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) { Log.d("PhotoHandler", "Can't create directory to save image."); Toast.makeText(context, "Can't create directory to save image.", Toast.LENGTH_LONG).show(); return; } Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); int width = bmp.getWidth(); int height = bmp.getHeight(); Matrix matrix = new Matrix(); matrix.postRotate(270); Bitmap rotatedBitmap = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, true); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); String date = dateFormat.format(new Date()); String photoFile = "Picture_" + date + ".jpg"; String filename = pictureFileDir.getPath() + File.separator + photoFile; File pictureFile = new File(filename); try { FileOutputStream fos = new FileOutputStream(pictureFile); boolean result = rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); //fos.write(bytes); fos.close(); if (result) { Toast.makeText(context, "New Image saved:" + photoFile, Toast.LENGTH_LONG).show(); } else { Toast.makeText(context, "Couldn't save image:" + photoFile, Toast.LENGTH_LONG).show(); } camera.startPreview(); } catch (Exception error) { Log.d("PhotoHandler", "File" + filename + "not saved: " + error.getMessage()); Toast.makeText(context, "Image could not be saved.", Toast.LENGTH_LONG).show(); } } private File getDir() { File sdDir = Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); return new File(sdDir, "CameraAPIDemo"); } } 

[AndroidManifest.xml]

 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.g5digital.cam2" > <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.FLASHLIGHT" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.g5digital.cam2.MainActivity" android:label="@string/app_name" android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> 

[Activity_main.xml]

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.g5digital.cam2.MainActivity" tools:ignore="MergeRootFrame"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/click" android:id="@+id/button" /> </LinearLayout> 

[Salida LogCat]

 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 D/MainActivity﹕ takePicture failed 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ java.lang.RuntimeException: takePicture failed 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.hardware.Camera.native_takePicture(Native Method) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.hardware.Camera.takePicture(Camera.java:1194) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.hardware.Camera.takePicture(Camera.java:1139) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at com.g5digital.cam2.MainActivity.onClick(MainActivity.java:66) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.view.View.performClick(View.java:4475) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.view.View$PerformClick.run(View.java:18786) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.os.Handler.handleCallback(Handler.java:730) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.os.Handler.dispatchMessage(Handler.java:92) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.os.Looper.loop(Looper.java:137) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.app.ActivityThread.main(ActivityThread.java:5419) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at java.lang.reflect.Method.invokeNative(Native Method) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at java.lang.reflect.Method.invoke(Method.java:525) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) 01-29 14:55:45.836 5853-5853/com.g5digital.cam2 W/System.err﹕ at dalvik.system.NativeStart.main(Native Method) 

No, para tomar una foto debe mostrar la vista previa. Se pueden tomar fotos con la cámara desde un servicio sin interfaz de usuario , Cómo utilizar la cámara para tomar una foto en un fondo Servicio en ¿Androide? …

Pero tenga en cuenta que el requisito no es para fines técnicos, sino de privacidad. Y el sistema continúa evolucionando y protegiéndose contra las nuevas soluciones encontradas.

Quizás la forma más robusta de ocultar vista previa en S4 es usar SurfaceTexture, pero mostrarlo de forma invisible, por ejemplo, desplazado fuera de la ventana gráfica.

  • Rendimiento de PDF de Android
  • Después de importar Android Project en Eclipse, los iconos de paquete son "blanco"
  • Sobreescribiendo el método onScroll del com.android.View en la codificación android?
  • Autodetección del lenguaje de un texto en Java (Android)
  • Simple exportación e importación de una base de datos SQLite en Android
  • Ejemplos de patrones de diseño de Android MVVM
  • Modificación inesperada del almacenamiento de contenido de Android Studio
  • ¿Por qué el diálogo personalizado de Android aparece en pantalla completa?
  • Cómo agregar funcionalidad de flecha de botón Volver en barra de navegación
  • ¿Cuáles son las limitaciones de Python en Android?
  • ¿Cómo puedo crear una miniatura de una url de vídeo en android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.