From f51815684839e196bcc8b478e75e40d77d9f3052 Mon Sep 17 00:00:00 2001 From: Mattia Iavarone Date: Sat, 14 Dec 2019 22:30:53 +0100 Subject: [PATCH] Add destroy depth --- .../cameraview/engine/Camera2Engine.java | 13 ++++---- .../cameraview/engine/CameraEngine.java | 30 +++++++++++++------ .../picture/Full1PictureRecorder.java | 4 +-- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java index 474d7fe9..f3a59228 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java @@ -638,20 +638,19 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv if (hasFrameProcessors()) { getFrameManager().release(); } + // Removing the part below for now. It hangs on emulators and can take a lot of time + // in real devices, for benefits that I'm not 100% sure about. if (false) { try { - // Preferring this over stopRepeating() so we're sure that all in-flights operations - // are discarded as fast as possible, which is exactly what we want. + // Preferring abortCaptures() over stopRepeating(): it makes sure that all + // in-flight operations are discarded as fast as possible, which is what we want. // NOTE: this call is asynchronous. Should find a good way to wait for the outcome. - LOG.i("onStopPreview:", "calling stopRepeating()."); - // TODO HANGS (rare, emulator only) - mSession.stopRepeating(); LOG.i("onStopPreview:", "calling abortCaptures()."); mSession.abortCaptures(); LOG.i("onStopPreview:", "called abortCaptures()."); } catch (CameraAccessException e) { - // This tells us that we should stop everything. It's better to throw an unrecoverable - // exception rather than just swallow this, so everything gets stopped. + // This tells us that we should stop everything. It's better to throw an + // unrecoverable exception rather than just swallow, so everything gets stopped. LOG.w("onStopPreview:", "abortCaptures failed!", e); throw createCameraException(e); } catch (IllegalStateException e) { diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java index 1d90f7cf..5f75d43f 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java @@ -137,6 +137,9 @@ public abstract class CameraEngine implements protected static final String TAG = CameraEngine.class.getSimpleName(); protected static final CameraLogger LOG = CameraLogger.create(TAG); + // If this is 2, this means we'll try to run destroy() twice. + private static final int DESTROY_RETRIES = 2; + // Need to be protected @SuppressWarnings("WeakerAccess") protected final Callback mCallback; @SuppressWarnings("WeakerAccess") protected CameraPreview mPreview; @@ -350,8 +353,13 @@ public abstract class CameraEngine implements * awaiting for {@link #stop(boolean)} to return. */ public void destroy(boolean unrecoverably) { + destroy(unrecoverably, 0); + } + + private void destroy(boolean unrecoverably, int depth) { LOG.i("DESTROY:", "state:", getState(), "thread:", Thread.currentThread(), + "depth:", depth, "unrecoverably:", unrecoverably); if (unrecoverably) { // Prevent CameraEngine leaks. Don't set to null, or exceptions @@ -363,11 +371,11 @@ public abstract class CameraEngine implements stop(true).addOnCompleteListener( mHandler.getExecutor(), new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - latch.countDown(); - } - }); + @Override + public void onComplete(@NonNull Task task) { + latch.countDown(); + } + }); try { boolean success = latch.await(6, TimeUnit.SECONDS); if (!success) { @@ -377,10 +385,14 @@ public abstract class CameraEngine implements LOG.e("DESTROY: Could not destroy synchronously after 6 seconds.", "Current thread:", Thread.currentThread(), "Handler thread:", mHandler.getThread()); - recreateHandler(true); - LOG.e("DESTROY: Could not destroy synchronously after 6 seconds.", - "Trying again on thread:", mHandler.getThread()); - destroy(unrecoverably); + depth++; + if (depth < DESTROY_RETRIES) { + recreateHandler(true); + LOG.e("DESTROY: Trying again on thread:", mHandler.getThread()); + destroy(unrecoverably, depth); + } else { + LOG.w("DESTROY: Giving up because DESTROY_RETRIES was reached."); + } } } catch (InterruptedException ignore) {} } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full1PictureRecorder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full1PictureRecorder.java index d6936c9a..7690419b 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full1PictureRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full1PictureRecorder.java @@ -38,8 +38,8 @@ public class Full1PictureRecorder extends FullPictureRecorder { @Override public void take() { LOG.i("take() called."); - // TODO HANGS (rare, emulator only) - // Trying to fix by stopping preview callback before. + // Stopping the preview callback is important on older APIs / emulators, + // or takePicture can hang and leave the camera in a bad state. mCamera.setPreviewCallbackWithBuffer(null); mCamera.takePicture( new Camera.ShutterCallback() {