diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 089b2c2222..81e8fd45b1 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.10.5+5 + +* Fixes bug where old camera resources were not disposed when switching between camera descriptions. +* Fixes bug where _deviceOrientationSubscription was recreated every time the camera description was + changed. + ## 0.10.5+4 * Adds pub topics to package metadata. diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index c907980b26..2e8d0df8d7 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -265,7 +265,10 @@ class CameraController extends ValueNotifier { bool _isDisposed = false; StreamSubscription? _imageStreamSubscription; - FutureOr? _initCalled; + // A Future awaiting an attempt to initialize (e.g. after `initialize` was + // just called). If the controller has not been initialized at least once, + // this value is null. + Future? _initializeFuture; StreamSubscription? _deviceOrientationSubscription; @@ -294,11 +297,15 @@ class CameraController extends ValueNotifier { 'initialize was called on a disposed CameraController', ); } + + final Completer initializeCompleter = Completer(); + _initializeFuture = initializeCompleter.future; + try { final Completer initializeCompleter = Completer(); - _deviceOrientationSubscription = CameraPlatform.instance + _deviceOrientationSubscription ??= CameraPlatform.instance .onDeviceOrientationChanged() .listen((DeviceOrientationChangedEvent event) { value = value.copyWith( @@ -343,9 +350,9 @@ class CameraController extends ValueNotifier { ); } on PlatformException catch (e) { throw CameraException(e.code, e.message); + } finally { + initializeCompleter.complete(); } - - _initCalled = true; } /// Prepare the capture session for video recording. @@ -402,6 +409,11 @@ class CameraController extends ValueNotifier { await CameraPlatform.instance.setDescriptionWhileRecording(description); value = value.copyWith(description: description); } else { + if (_initializeFuture != null) { + await _initializeFuture; + await CameraPlatform.instance.dispose(_cameraId); + } + await _initializeWithDescription(description); } } @@ -841,8 +853,8 @@ class CameraController extends ValueNotifier { _unawaited(_deviceOrientationSubscription?.cancel()); _isDisposed = true; super.dispose(); - if (_initCalled != null) { - await _initCalled; + if (_initializeFuture != null) { + await _initializeFuture; await CameraPlatform.instance.dispose(_cameraId); } } diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index b8b94f127d..c246e4c232 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing Dart. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.10.5+4 +version: 0.10.5+5 environment: sdk: ">=2.19.0 <4.0.0" diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index ab8354f7ba..ec111ed859 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -192,6 +192,42 @@ void main() { .called(1); }); + test('setDescription waits for initialize before calling dispose', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90, + ), + ResolutionPreset.max, + imageFormatGroup: ImageFormatGroup.bgra8888, + ); + + final Completer initializeCompleter = Completer(); + when(CameraPlatform.instance.initializeCamera( + mockInitializeCamera, + imageFormatGroup: ImageFormatGroup.bgra8888, + )).thenAnswer( + (_) => initializeCompleter.future, + ); + + unawaited(cameraController.initialize()); + + final Future setDescriptionFuture = cameraController.setDescription( + const CameraDescription( + name: 'cam2', + lensDirection: CameraLensDirection.front, + sensorOrientation: 90), + ); + verifyNever(CameraPlatform.instance.dispose(mockInitializeCamera)); + + initializeCompleter.complete(); + + await setDescriptionFuture; + verify(CameraPlatform.instance.dispose(mockInitializeCamera)); + }); + test('prepareForVideoRecording() calls $CameraPlatform ', () async { final CameraController cameraController = CameraController( const CameraDescription(