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]
- Obtención de la API de Preferencias en Android y PC
- ¿Cómo puedo agregar datos que he introducido en un cuadro de EditText en una matriz para enumerar en otra actividad?
- Parametrización de Android @Headers
- OpenCV - Java: función inRange
- ¿Qué pasó con la java de Emacs?
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)
- Parse + Robolectric causando java.lang.VerifyError: Tipo incorrecto en pila de operandos
- XmlPullParserException función no admitida
- Comenzando con Android: Java o Python (SL4A)
- Utilizando RxJava para la validación de inicio de sesión de correo electrónico, un observable está emitiendo dos veces
- Aplicación para Android que toma mucha memoria
- Cómo tratar los problemas de la red
- ¿Cómo enviar una respuesta de PHP a una aplicación móvil de Android / Java?
- Android: EfficientAdapter con dos vistas diferentes
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.
- Cómo abrir la aplicación Google Play Store desde mi aplicación para instalar la versión más reciente de mi aplicación disponible en la tienda de reproducción
- Android.grapics.matrix to OpenGL 2.0 ES traducción de la textura