diff --git a/packages/camera/camera_android_camerax/CHANGELOG.md b/packages/camera/camera_android_camerax/CHANGELOG.md index a98f51e54eae..4492d39d7e1c 100644 --- a/packages/camera/camera_android_camerax/CHANGELOG.md +++ b/packages/camera/camera_android_camerax/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.7.2+2 + +* Fixes a `StateError` ("Bad state: No element") in `setFocusMode(FocusMode.auto)` + when the current focus and metering action has no auto-focus points. + ## 0.7.2+1 * Migrates to Built-in Kotlin to support AGP 9. diff --git a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart index 0c84bdf2f2e5..7d5b7d3e257f 100644 --- a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart +++ b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart @@ -632,9 +632,12 @@ class AndroidCameraCameraX extends CameraPlatform { case FocusMode.auto: // Determine auto-focus point to restore, if any. We do not restore // default auto-focus point if set previously to lock focus. - final MeteringPoint? unLockedFocusPoint = _defaultFocusPointLocked + final List possibleCurrentAfPoints = + currentFocusMeteringAction?.meteringPointsAf ?? []; + final MeteringPoint? unLockedFocusPoint = + _defaultFocusPointLocked || possibleCurrentAfPoints.isEmpty ? null - : currentFocusMeteringAction!.meteringPointsAf.first; + : possibleCurrentAfPoints.first; _defaultFocusPointLocked = false; autoFocusPoint = unLockedFocusPoint; disableAutoCancel = false; diff --git a/packages/camera/camera_android_camerax/pubspec.yaml b/packages/camera/camera_android_camerax/pubspec.yaml index e5fbd9bf008e..ae99c02beb0d 100644 --- a/packages/camera/camera_android_camerax/pubspec.yaml +++ b/packages/camera/camera_android_camerax/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_android_camerax description: Android implementation of the camera plugin using the CameraX library. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android_camerax issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.7.2+1 +version: 0.7.2+2 environment: sdk: ^3.12.0 diff --git a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart index afc297894d29..03320e2d5542 100644 --- a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart +++ b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart @@ -4967,6 +4967,44 @@ void main() { }, ); + test( + 'setFocusMode does not throw when setting auto-focus mode and the current focus and metering action has no auto-focus point', + () async { + final camera = AndroidCameraCameraX(); + const cameraId = 11; + final mockCameraControl = MockCameraControl(); + final FocusMeteringResult mockFocusMeteringResult = MockFocusMeteringResult(); + final mockCamera2CameraControl = MockCamera2CameraControl(); + const point = Point(0.1, 0.2); + + // Set directly for test versus calling createCamera. + camera.cameraInfo = MockCameraInfo(); + camera.cameraControl = mockCameraControl; + + when( + mockCamera2CameraControl.addCaptureRequestOptions(any), + ).thenAnswer((_) async => Future.value()); + + setUpOverridesForSettingFocusandExposurePoints(mockCameraControl, mockCamera2CameraControl); + + // Make setting focus and metering action successful for test. + when(mockFocusMeteringResult.isFocusSuccessful).thenReturn(true); + when( + mockCameraControl.startFocusAndMetering(any), + ).thenAnswer((_) async => Future.value(mockFocusMeteringResult)); + + // Lock focus while an auto-focus point exists, then clear it, leaving a + // non-null action whose auto-focus point list is empty. + await camera.setExposurePoint(cameraId, point); + await camera.setFocusPoint(cameraId, point); + await camera.setFocusMode(cameraId, FocusMode.locked); + await camera.setFocusPoint(cameraId, null); + + // Switching back to auto-focus must not throw. + await expectLater(camera.setFocusMode(cameraId, FocusMode.auto), completes); + }, + ); + test( 'setFocusMode starts expected focus and metering action with previously set auto-focus point if setting locked focus mode and current focus and metering action has auto-focus point', () async {