add try catch to catch exceptions when takePicture fails (#1024)

* add try catch to catch exceptions when takePicture fails, to give the user a better experience than an app crash

* do not log errors, as they are alreayd logged by the camera engine, and do not put try catch around DNG captures

Co-authored-by: Mattia Iavarone <mat.iavarone@gmail.com>
pull/1030/head
Michael 4 years ago committed by GitHub
parent 0f6ab20c3e
commit 5d10277d7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraUtils.java
  2. 99
      cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full1PictureRecorder.java
  3. 9
      cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full2PictureRecorder.java

@ -158,7 +158,7 @@ public class CameraUtils {
@NonNull final BitmapCallback callback) { @NonNull final BitmapCallback callback) {
decodeBitmap(source, Integer.MAX_VALUE, Integer.MAX_VALUE, callback); decodeBitmap(source, Integer.MAX_VALUE, Integer.MAX_VALUE, callback);
} }
/** /**
* Decodes an input byte array and outputs a Bitmap that is ready to be displayed. * Decodes an input byte array and outputs a Bitmap that is ready to be displayed.
* The difference with {@link android.graphics.BitmapFactory#decodeByteArray(byte[], int, int)} * The difference with {@link android.graphics.BitmapFactory#decodeByteArray(byte[], int, int)}

@ -1,10 +1,12 @@
package com.otaliastudios.cameraview.picture; package com.otaliastudios.cameraview.picture;
import android.hardware.Camera; import android.hardware.Camera;
import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.exifinterface.media.ExifInterface; import androidx.exifinterface.media.ExifInterface;
import com.otaliastudios.cameraview.CameraException;
import com.otaliastudios.cameraview.PictureResult; import com.otaliastudios.cameraview.PictureResult;
import com.otaliastudios.cameraview.engine.Camera1Engine; import com.otaliastudios.cameraview.engine.Camera1Engine;
import com.otaliastudios.cameraview.engine.offset.Reference; import com.otaliastudios.cameraview.engine.offset.Reference;
@ -44,57 +46,62 @@ public class Full1PictureRecorder extends FullPictureRecorder {
// or takePicture can hang and leave the camera in a bad state. // or takePicture can hang and leave the camera in a bad state.
mCamera.setPreviewCallbackWithBuffer(null); mCamera.setPreviewCallbackWithBuffer(null);
mEngine.getFrameManager().release(); mEngine.getFrameManager().release();
mCamera.takePicture( try {
new Camera.ShutterCallback() { mCamera.takePicture(
@Override new Camera.ShutterCallback() {
public void onShutter() { @Override
LOG.i("take(): got onShutter callback."); public void onShutter() {
dispatchOnShutter(true); LOG.i("take(): got onShutter callback.");
} dispatchOnShutter(true);
},
null,
null,
new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, final Camera camera) {
LOG.i("take(): got picture callback.");
int exifRotation;
try {
ExifInterface exif = new ExifInterface(new ByteArrayInputStream(data));
int exifOrientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
exifRotation = ExifHelper.getOrientation(exifOrientation);
} catch (IOException e) {
exifRotation = 0;
} }
mResult.data = data; },
mResult.rotation = exifRotation; null,
LOG.i("take(): starting preview again. ", Thread.currentThread()); null,
new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, final Camera camera) {
LOG.i("take(): got picture callback.");
int exifRotation;
try {
ExifInterface exif = new ExifInterface(new ByteArrayInputStream(data));
int exifOrientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
exifRotation = ExifHelper.getOrientation(exifOrientation);
} catch (IOException e) {
exifRotation = 0;
}
mResult.data = data;
mResult.rotation = exifRotation;
LOG.i("take(): starting preview again. ", Thread.currentThread());
// It's possible that by the time this callback is invoked, we're not previewing // It's possible that by the time this callback is invoked, we're not previewing
// anymore, so check before restarting preview. // anymore, so check before restarting preview.
if (mEngine.getState().isAtLeast(CameraState.PREVIEW)) { if (mEngine.getState().isAtLeast(CameraState.PREVIEW)) {
camera.setPreviewCallbackWithBuffer(mEngine); camera.setPreviewCallbackWithBuffer(mEngine);
Size previewStreamSize = mEngine.getPreviewStreamSize(Reference.SENSOR); Size previewStreamSize = mEngine.getPreviewStreamSize(Reference.SENSOR);
if (previewStreamSize == null) { if (previewStreamSize == null) {
throw new IllegalStateException("Preview stream size " + throw new IllegalStateException("Preview stream size " +
"should never be null here."); "should never be null here.");
}
// Need to re-setup the frame manager, otherwise no frames are processed
// after takePicture() is called
mEngine.getFrameManager().setUp(
mEngine.getFrameProcessingFormat(),
previewStreamSize,
mEngine.getAngles()
);
camera.startPreview();
} }
// Need to re-setup the frame manager, otherwise no frames are processed dispatchResult();
// after takePicture() is called
mEngine.getFrameManager().setUp(
mEngine.getFrameProcessingFormat(),
previewStreamSize,
mEngine.getAngles()
);
camera.startPreview();
} }
dispatchResult();
} }
} );
); LOG.i("take() returned.");
LOG.i("take() returned."); } catch (Exception e) {
mError = e;
dispatchResult();
}
} }
@Override @Override

@ -8,6 +8,7 @@ import android.hardware.camera2.TotalCaptureResult;
import android.media.Image; import android.media.Image;
import android.media.ImageReader; import android.media.ImageReader;
import android.os.Build; import android.os.Build;
import android.util.Log;
import com.otaliastudios.cameraview.PictureResult; import com.otaliastudios.cameraview.PictureResult;
import com.otaliastudios.cameraview.controls.PictureFormat; import com.otaliastudios.cameraview.controls.PictureFormat;
@ -86,7 +87,13 @@ public class Full2PictureRecorder extends FullPictureRecorder
public void onCaptureCompleted(@NonNull ActionHolder holder, public void onCaptureCompleted(@NonNull ActionHolder holder,
@NonNull CaptureRequest request, @NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) { @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(holder, request, result); try {
super.onCaptureCompleted(holder, request, result);
} catch (Exception e) {
mError = e;
dispatchResult();
}
if (mResult.format == PictureFormat.DNG) { if (mResult.format == PictureFormat.DNG) {
mDngCreator = new DngCreator(holder.getCharacteristics(this), result); mDngCreator = new DngCreator(holder.getCharacteristics(this), result);
mDngCreator.setOrientation(ExifHelper.getExifOrientation(mResult.rotation)); mDngCreator.setOrientation(ExifHelper.getExifOrientation(mResult.rotation));

Loading…
Cancel
Save