diff --git a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java index b4f89adef9a3..f76a1cde5eac 100644 --- a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -12,6 +12,7 @@ import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; @@ -675,13 +676,39 @@ private void runPrecaptureSequence() { // Trigger one capture to start AE sequence. captureSession.capture( - previewRequestBuilder.build(), cameraCaptureCallback, backgroundHandler); + previewRequestBuilder.build(), + createTriggerResetCallback( + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE), + backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } + @VisibleForTesting + CameraCaptureSession.CaptureCallback createTriggerResetCallback( + final CaptureRequest.Key triggerKey, final int triggerIdleValue) { + return new CameraCaptureSession.CaptureCallback() { + @Override + public void onCaptureCompleted( + @NonNull CameraCaptureSession session, + @NonNull CaptureRequest request, + @NonNull TotalCaptureResult result) { + previewRequestBuilder.set(triggerKey, triggerIdleValue); + } + + @Override + public void onCaptureFailed( + @NonNull CameraCaptureSession session, + @NonNull CaptureRequest request, + @NonNull CaptureFailure failure) { + previewRequestBuilder.set(triggerKey, triggerIdleValue); + } + }; + } + /** * Capture a still picture. This method should be called when a response is received {@link * #cameraCaptureCallback} from both lockFocus(). @@ -788,7 +815,11 @@ private void lockAutoFocus() { CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); try { - captureSession.capture(previewRequestBuilder.build(), null, backgroundHandler); + captureSession.capture( + previewRequestBuilder.build(), + createTriggerResetCallback( + CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE), + backgroundHandler); } catch (CameraAccessException e) { String message = (e.getMessage() == null) diff --git a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java index 9b2b4ffeec81..0a73e0a29752 100644 --- a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java +++ b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java @@ -976,6 +976,62 @@ public void setFocusMode_shouldSendErrorEventOnLockAutoFocusCameraAccessExceptio verify(mockDartMessenger, times(1)).sendCameraErrorEvent(any()); } + @Test + public void createTriggerResetCallback_shouldResetTriggerOnCaptureCompleted() { + CaptureRequest.Key triggerKey = CaptureRequest.CONTROL_AF_TRIGGER; + int idleValue = CameraMetadata.CONTROL_AF_TRIGGER_IDLE; + + CameraCaptureSession.CaptureCallback callback = + camera.createTriggerResetCallback(triggerKey, idleValue); + + callback.onCaptureCompleted( + mock(CameraCaptureSession.class), mock(CaptureRequest.class), mock(TotalCaptureResult.class)); + + verify(mockPreviewRequestBuilder, times(1)).set(triggerKey, idleValue); + } + + @Test + public void createTriggerResetCallback_shouldResetTriggerOnCaptureFailed() { + CaptureRequest.Key triggerKey = CaptureRequest.CONTROL_AF_TRIGGER; + int idleValue = CameraMetadata.CONTROL_AF_TRIGGER_IDLE; + + CameraCaptureSession.CaptureCallback callback = + camera.createTriggerResetCallback(triggerKey, idleValue); + + callback.onCaptureFailed( + mock(CameraCaptureSession.class), mock(CaptureRequest.class), mock(CaptureFailure.class)); + + verify(mockPreviewRequestBuilder, times(1)).set(triggerKey, idleValue); + } + + @Test + public void createTriggerResetCallback_shouldResetAEPrecaptureTriggerOnCaptureCompleted() { + CaptureRequest.Key triggerKey = CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER; + int idleValue = CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE; + + CameraCaptureSession.CaptureCallback callback = + camera.createTriggerResetCallback(triggerKey, idleValue); + + callback.onCaptureCompleted( + mock(CameraCaptureSession.class), mock(CaptureRequest.class), mock(TotalCaptureResult.class)); + + verify(mockPreviewRequestBuilder, times(1)).set(triggerKey, idleValue); + } + + @Test + public void createTriggerResetCallback_shouldResetAEPrecaptureTriggerOnCaptureFailed() { + CaptureRequest.Key triggerKey = CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER; + int idleValue = CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE; + + CameraCaptureSession.CaptureCallback callback = + camera.createTriggerResetCallback(triggerKey, idleValue); + + callback.onCaptureFailed( + mock(CameraCaptureSession.class), mock(CaptureRequest.class), mock(CaptureFailure.class)); + + verify(mockPreviewRequestBuilder, times(1)).set(triggerKey, idleValue); + } + @Test public void setFocusMode_shouldCallErrorOnResultOnCameraAccessException() throws CameraAccessException {