From fc073eb1fad25fd8c60ffbb8c30b637e86a7ec60 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 19 Mar 2024 11:10:08 -0700 Subject: [PATCH 01/10] Add aspect ratio where I can --- .../lib/src/android_camera_camerax.dart | 21 ++++++++++++++++--- .../lib/src/camerax_proxy.dart | 7 ++++--- 2 files changed, 22 insertions(+), 6 deletions(-) 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 1612ab512d3..5e547c18f0c 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 @@ -9,10 +9,11 @@ import 'package:async/async.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/services.dart' show DeviceOrientation, PlatformException; -import 'package:flutter/widgets.dart'; +import 'package:flutter/widgets.dart' hide AspectRatio; import 'package:stream_transform/stream_transform.dart'; import 'analyzer.dart'; +import 'aspect_ratio_strategy.dart'; import 'camera.dart'; import 'camera2_camera_control.dart'; import 'camera_control.dart'; @@ -1150,32 +1151,46 @@ class AndroidCameraCameraX extends CameraPlatform { ResolutionStrategy.fallbackRuleClosestLowerThenHigher; Size? boundSize; + int? aspectRatio; ResolutionStrategy? resolutionStrategy; switch (preset) { case ResolutionPreset.low: boundSize = const Size(320, 240); + aspectRatio = AspectRatio.ratio4To3; case ResolutionPreset.medium: + // TODO(camsim99): Handle the 3:2 aspect ratio case: + // https://github.com/flutter/flutter/issues/144363. boundSize = const Size(720, 480); case ResolutionPreset.high: boundSize = const Size(1280, 720); + aspectRatio = AspectRatio.ratio16To9; case ResolutionPreset.veryHigh: boundSize = const Size(1920, 1080); + aspectRatio = AspectRatio.ratio16To9; case ResolutionPreset.ultraHigh: boundSize = const Size(3840, 2160); + aspectRatio = AspectRatio.ratio16To9; case ResolutionPreset.max: // Automatically set strategy to choose highest available. resolutionStrategy = proxy.createResolutionStrategy(highestAvailable: true); - return proxy.createResolutionSelector(resolutionStrategy); + return proxy.createResolutionSelector( + resolutionStrategy, /* AspectRatioStrategy */ null); case null: // If no preset is specified, default to CameraX's default behavior // for each UseCase. return null; } + final AspectRatioStrategy? aspectRatioStrategy = aspectRatio == null + ? null + : AspectRatioStrategy( + preferredAspectRatio: aspectRatio, + fallbackRule: AspectRatioStrategy.fallbackRuleAuto); resolutionStrategy = proxy.createResolutionStrategy( boundSize: boundSize, fallbackRule: fallbackRule); - return proxy.createResolutionSelector(resolutionStrategy); + return proxy.createResolutionSelector( + resolutionStrategy, aspectRatioStrategy); } /// Returns the [QualitySelector] that maps to the specified resolution diff --git a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart index fb100ddb20a..b8f22822ff0 100644 --- a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart +++ b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart @@ -5,6 +5,7 @@ import 'dart:ui' show Size; import 'analyzer.dart'; +import 'aspect_ratio_strategy.dart'; import 'camera2_camera_control.dart'; import 'camera_control.dart'; import 'camera_info.dart'; @@ -116,7 +117,7 @@ class CameraXProxy { /// Returns a [ResolutionSelector] configured with the specified /// [ResolutionStrategy]. - ResolutionSelector Function(ResolutionStrategy resolutionStrategy) + ResolutionSelector Function(ResolutionStrategy resolutionStrategy, AspectRatioStrategy? aspectRatioStrategy) createResolutionSelector; /// Returns a [FallbackStrategy] configured with the specified [VideoQuality] @@ -234,8 +235,8 @@ class CameraXProxy { } static ResolutionSelector _createAttachedResolutionSelector( - ResolutionStrategy resolutionStrategy) { - return ResolutionSelector(resolutionStrategy: resolutionStrategy); + ResolutionStrategy resolutionStrategy, AspectRatioStrategy? aspectRatioStrategy) { + return ResolutionSelector(resolutionStrategy: resolutionStrategy, aspectRatioStrategy: aspectRatioStrategy); } static FallbackStrategy _createAttachedFallbackStrategy( From a0da39895dbe3b6fd4a166974f99f94902eeb45c Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 19 Mar 2024 11:34:03 -0700 Subject: [PATCH 02/10] Start adding tests --- .../lib/src/android_camera_camerax.dart | 3 +- .../lib/src/camerax_proxy.dart | 13 +- .../test/android_camera_camerax_test.dart | 265 +++++++++++------- 3 files changed, 169 insertions(+), 112 deletions(-) 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 5e547c18f0c..d12ecfd188b 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 @@ -9,7 +9,8 @@ import 'package:async/async.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/services.dart' show DeviceOrientation, PlatformException; -import 'package:flutter/widgets.dart' hide AspectRatio; +import 'package:flutter/widgets.dart' + show Size, Texture, Widget, visibleForTesting; import 'package:stream_transform/stream_transform.dart'; import 'analyzer.dart'; diff --git a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart index b8f22822ff0..6096fc308da 100644 --- a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart +++ b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart @@ -116,9 +116,9 @@ class CameraXProxy { int? fallbackRule}) createResolutionStrategy; /// Returns a [ResolutionSelector] configured with the specified - /// [ResolutionStrategy]. - ResolutionSelector Function(ResolutionStrategy resolutionStrategy, AspectRatioStrategy? aspectRatioStrategy) - createResolutionSelector; + /// [ResolutionStrategy] and [AspectRatioStrategy]. + ResolutionSelector Function(ResolutionStrategy resolutionStrategy, + AspectRatioStrategy? aspectRatioStrategy) createResolutionSelector; /// Returns a [FallbackStrategy] configured with the specified [VideoQuality] /// and [VideoResolutionFallbackRule]. @@ -235,8 +235,11 @@ class CameraXProxy { } static ResolutionSelector _createAttachedResolutionSelector( - ResolutionStrategy resolutionStrategy, AspectRatioStrategy? aspectRatioStrategy) { - return ResolutionSelector(resolutionStrategy: resolutionStrategy, aspectRatioStrategy: aspectRatioStrategy); + ResolutionStrategy resolutionStrategy, + AspectRatioStrategy? aspectRatioStrategy) { + return ResolutionSelector( + resolutionStrategy: resolutionStrategy, + aspectRatioStrategy: aspectRatioStrategy); } static FallbackStrategy _createAttachedFallbackStrategy( 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 d9ff081383e..b8daa14fd12 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 @@ -8,6 +8,7 @@ import 'dart:math' show Point; import 'package:async/async.dart'; import 'package:camera_android_camerax/camera_android_camerax.dart'; import 'package:camera_android_camerax/src/analyzer.dart'; +import 'package:camera_android_camerax/src/aspect_ratio_strategy.dart'; import 'package:camera_android_camerax/src/camera.dart'; import 'package:camera_android_camerax/src/camera2_camera_control.dart'; import 'package:camera_android_camerax/src/camera_control.dart'; @@ -122,6 +123,65 @@ void main() { return cameraClosingEventSent && cameraErrorSent; } + /// CameraXProxy for testing functionality related to the camera resolution + /// preset (setting expected ResolutionSelectors, QualitySelectors, etc.). + CameraXProxy getProxyForTestingResolutionPreset( + MockProcessCameraProvider mockProcessCameraProvider) => + CameraXProxy( + getProcessCameraProvider: () => + Future.value(mockProcessCameraProvider), + createCameraSelector: (int cameraSelectorLensDirection) => + MockCameraSelector(), + createPreview: + (ResolutionSelector? resolutionSelector, int? targetRotation) => + Preview.detached( + initialTargetRotation: targetRotation, + resolutionSelector: resolutionSelector), + createImageCapture: + (ResolutionSelector? resolutionSelector, int? targetRotation) => + ImageCapture.detached( + resolutionSelector: resolutionSelector, + initialTargetRotation: targetRotation), + createRecorder: (QualitySelector? qualitySelector) => + Recorder.detached(qualitySelector: qualitySelector), + createVideoCapture: (_) => + Future.value(MockVideoCapture()), + createImageAnalysis: + (ResolutionSelector? resolutionSelector, int? targetRotation) => + ImageAnalysis.detached( + resolutionSelector: resolutionSelector, + initialTargetRotation: targetRotation), + createResolutionStrategy: ( + {bool highestAvailable = false, + Size? boundSize, + int? fallbackRule}) { + if (highestAvailable) { + return ResolutionStrategy.detachedHighestAvailableStrategy(); + } + + return ResolutionStrategy.detached( + boundSize: boundSize, fallbackRule: fallbackRule); + }, + createResolutionSelector: (ResolutionStrategy resolutionStrategy, + AspectRatioStrategy? aspectRatioStrategy) => + ResolutionSelector.detached( + resolutionStrategy: resolutionStrategy, + aspectRatioStrategy: aspectRatioStrategy), + createFallbackStrategy: ( + {required VideoQuality quality, + required VideoResolutionFallbackRule fallbackRule}) => + MockFallbackStrategy(), + createQualitySelector: ( + {required VideoQuality videoQuality, + required FallbackStrategy fallbackStrategy}) => + MockQualitySelector(), + createCameraStateObserver: (_) => MockObserver(), + requestCameraPermissions: (_) => Future.value(), + startListeningForDeviceOrientationChange: (_, __) {}, + setPreviewSurfaceProvider: (_) => Future.value( + 3), // 3 is a random Flutter SurfaceTexture ID for testing}, + ); + /// CameraXProxy for testing exposure and focus related controls. /// /// Modifies the creation of [MeteringPoint]s and [FocusMeteringAction]s to @@ -289,7 +349,7 @@ void main() { Size? boundSize, int? fallbackRule}) => MockResolutionStrategy(), - createResolutionSelector: (_) => MockResolutionSelector(), + createResolutionSelector: (_, __) => MockResolutionSelector(), createFallbackStrategy: ( {required VideoQuality quality, required VideoResolutionFallbackRule fallbackRule}) => @@ -405,7 +465,7 @@ void main() { Size? boundSize, int? fallbackRule}) => MockResolutionStrategy(), - createResolutionSelector: (_) => MockResolutionSelector(), + createResolutionSelector: (_, __) => MockResolutionSelector(), createFallbackStrategy: ( {required VideoQuality quality, required VideoResolutionFallbackRule fallbackRule}) => @@ -466,69 +526,103 @@ void main() { final MockProcessCameraProvider mockProcessCameraProvider = MockProcessCameraProvider(); final MockCameraInfo mockCameraInfo = MockCameraInfo(); - final MockCameraSelector mockBackCameraSelector = MockCameraSelector(); - final MockCameraSelector mockFrontCameraSelector = MockCameraSelector(); - final MockVideoCapture mockVideoCapture = MockVideoCapture(); - final MockRecorder mockRecorder = MockRecorder(); // Tell plugin to create mock/detached objects for testing createCamera // as needed. - camera.proxy = CameraXProxy( - getProcessCameraProvider: () => - Future.value(mockProcessCameraProvider), - createCameraSelector: (int cameraSelectorLensDirection) { - switch (cameraSelectorLensDirection) { - case CameraSelector.lensFacingFront: - return mockFrontCameraSelector; - case CameraSelector.lensFacingBack: - default: - return mockBackCameraSelector; - } - }, - createPreview: - (ResolutionSelector? resolutionSelector, int? targetRotation) => - Preview.detached( - initialTargetRotation: targetRotation, - resolutionSelector: resolutionSelector), - createImageCapture: - (ResolutionSelector? resolutionSelector, int? targetRotation) => - ImageCapture.detached( - resolutionSelector: resolutionSelector, - initialTargetRotation: targetRotation), - createRecorder: (_) => mockRecorder, - createVideoCapture: (_) => Future.value(mockVideoCapture), - createImageAnalysis: - (ResolutionSelector? resolutionSelector, int? targetRotation) => - ImageAnalysis.detached( - resolutionSelector: resolutionSelector, - initialTargetRotation: targetRotation), - createResolutionStrategy: ( - {bool highestAvailable = false, Size? boundSize, int? fallbackRule}) { - if (highestAvailable) { - return ResolutionStrategy.detachedHighestAvailableStrategy(); - } + camera.proxy = + getProxyForTestingResolutionPreset(mockProcessCameraProvider); - return ResolutionStrategy.detached( - boundSize: boundSize, fallbackRule: fallbackRule); - }, - createResolutionSelector: (ResolutionStrategy resolutionStrategy) => - ResolutionSelector.detached(resolutionStrategy: resolutionStrategy), - createFallbackStrategy: ( - {required VideoQuality quality, - required VideoResolutionFallbackRule fallbackRule}) => - MockFallbackStrategy(), - createQualitySelector: ( - {required VideoQuality videoQuality, - required FallbackStrategy fallbackStrategy}) => - MockQualitySelector(), - createCameraStateObserver: (_) => MockObserver(), - requestCameraPermissions: (_) => Future.value(), - startListeningForDeviceOrientationChange: (_, __) {}, - setPreviewSurfaceProvider: (_) => Future.value( - 3), // 3 is a random Flutter SurfaceTexture ID for testing}, - ); + when(mockProcessCameraProvider.bindToLifecycle(any, any)) + .thenAnswer((_) async => mockCamera); + when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); + when(mockCameraInfo.getCameraState()) + .thenAnswer((_) async => MockLiveCameraState()); + camera.processCameraProvider = mockProcessCameraProvider; - when(mockProcessCameraProvider.bindToLifecycle(mockBackCameraSelector, any)) + // Test non-null resolution presets. + for (final ResolutionPreset resolutionPreset in ResolutionPreset.values) { + await camera.createCamera(testCameraDescription, resolutionPreset, + enableAudio: enableAudio); + + Size? expectedBoundSize; + ResolutionStrategy? expectedResolutionStrategy; + switch (resolutionPreset) { + case ResolutionPreset.low: + expectedBoundSize = const Size(320, 240); + case ResolutionPreset.medium: + expectedBoundSize = const Size(720, 480); + case ResolutionPreset.high: + expectedBoundSize = const Size(1280, 720); + case ResolutionPreset.veryHigh: + expectedBoundSize = const Size(1920, 1080); + case ResolutionPreset.ultraHigh: + expectedBoundSize = const Size(3840, 2160); + case ResolutionPreset.max: + expectedResolutionStrategy = + ResolutionStrategy.detachedHighestAvailableStrategy(); + } + + // We expect the strategy to be the highest available or correspond to the + // expected bound size, with fallback to the closest and highest available + // resolution. + expectedResolutionStrategy ??= ResolutionStrategy.detached( + boundSize: expectedBoundSize, + fallbackRule: ResolutionStrategy.fallbackRuleClosestLowerThenHigher); + + expect(camera.preview!.resolutionSelector!.resolutionStrategy!.boundSize, + equals(expectedResolutionStrategy.boundSize)); + expect( + camera + .imageCapture!.resolutionSelector!.resolutionStrategy!.boundSize, + equals(expectedResolutionStrategy.boundSize)); + expect( + camera + .imageAnalysis!.resolutionSelector!.resolutionStrategy!.boundSize, + equals(expectedResolutionStrategy.boundSize)); + expect( + camera.preview!.resolutionSelector!.resolutionStrategy!.fallbackRule, + equals(expectedResolutionStrategy.fallbackRule)); + expect( + camera.imageCapture!.resolutionSelector!.resolutionStrategy! + .fallbackRule, + equals(expectedResolutionStrategy.fallbackRule)); + expect( + camera.imageAnalysis!.resolutionSelector!.resolutionStrategy! + .fallbackRule, + equals(expectedResolutionStrategy.fallbackRule)); + } + + // Test null case. + await camera.createCamera(testCameraDescription, null); + expect(camera.preview!.resolutionSelector, isNull); + expect(camera.imageCapture!.resolutionSelector, isNull); + expect(camera.imageAnalysis!.resolutionSelector, isNull); + }); + + test( + 'createCamera properly sets aspect ratio based on preset resolution for non-video capture use cases', + () async { + final AndroidCameraCameraX camera = AndroidCameraCameraX(); + const CameraLensDirection testLensDirection = CameraLensDirection.back; + const int testSensorOrientation = 90; + const CameraDescription testCameraDescription = CameraDescription( + name: 'cameraName', + lensDirection: testLensDirection, + sensorOrientation: testSensorOrientation); + const bool enableAudio = true; + final MockCamera mockCamera = MockCamera(); + + // Mock/Detached objects for (typically attached) objects created by + // createCamera. + final MockProcessCameraProvider mockProcessCameraProvider = + MockProcessCameraProvider(); + final MockCameraInfo mockCameraInfo = MockCameraInfo(); + + // Tell plugin to create mock/detached objects for testing createCamera + // as needed. + camera.proxy = + getProxyForTestingResolutionPreset(mockProcessCameraProvider); + when(mockProcessCameraProvider.bindToLifecycle(any, any)) .thenAnswer((_) async => mockCamera); when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); when(mockCameraInfo.getCameraState()) @@ -613,58 +707,17 @@ void main() { final MockProcessCameraProvider mockProcessCameraProvider = MockProcessCameraProvider(); final MockCameraInfo mockCameraInfo = MockCameraInfo(); - final MockCameraSelector mockBackCameraSelector = MockCameraSelector(); - final MockCameraSelector mockFrontCameraSelector = MockCameraSelector(); final MockPreview mockPreview = MockPreview(); final MockImageCapture mockImageCapture = MockImageCapture(); - final MockVideoCapture mockVideoCapture = MockVideoCapture(); final MockImageAnalysis mockImageAnalysis = MockImageAnalysis(); // Tell plugin to create mock/detached objects for testing createCamera // as needed. - camera.proxy = CameraXProxy( - getProcessCameraProvider: () => - Future.value(mockProcessCameraProvider), - createCameraSelector: (int cameraSelectorLensDirection) { - switch (cameraSelectorLensDirection) { - case CameraSelector.lensFacingFront: - return mockFrontCameraSelector; - case CameraSelector.lensFacingBack: - default: - return mockBackCameraSelector; - } - }, - createPreview: (_, __) => mockPreview, - createImageCapture: (_, __) => mockImageCapture, - createRecorder: (QualitySelector? qualitySelector) => - Recorder.detached(qualitySelector: qualitySelector), - createVideoCapture: (_) => Future.value(mockVideoCapture), - createImageAnalysis: (_, __) => mockImageAnalysis, - createResolutionStrategy: ( - {bool highestAvailable = false, - Size? boundSize, - int? fallbackRule}) => - MockResolutionStrategy(), - createResolutionSelector: (_) => MockResolutionSelector(), - createFallbackStrategy: ( - {required VideoQuality quality, - required VideoResolutionFallbackRule fallbackRule}) => - FallbackStrategy.detached( - quality: quality, fallbackRule: fallbackRule), - createQualitySelector: ( - {required VideoQuality videoQuality, - required FallbackStrategy fallbackStrategy}) => - QualitySelector.detached(qualityList: [ - VideoQualityData(quality: videoQuality) - ], fallbackStrategy: fallbackStrategy), - createCameraStateObserver: (void Function(Object) onChanged) => - Observer.detached(onChanged: onChanged), - requestCameraPermissions: (_) => Future.value(), - startListeningForDeviceOrientationChange: (_, __) {}, - ); + camera.proxy = + getProxyForTestingResolutionPreset(mockProcessCameraProvider); - when(mockProcessCameraProvider.bindToLifecycle(mockBackCameraSelector, - [mockPreview, mockImageCapture, mockImageAnalysis])) + when(mockProcessCameraProvider.bindToLifecycle( + any, [mockPreview, mockImageCapture, mockImageAnalysis])) .thenAnswer((_) async => mockCamera); when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); when(mockCameraInfo.getCameraState()) @@ -773,7 +826,7 @@ void main() { Size? boundSize, int? fallbackRule}) => MockResolutionStrategy(), - createResolutionSelector: (_) => MockResolutionSelector(), + createResolutionSelector: (_, __) => MockResolutionSelector(), createFallbackStrategy: ( {required VideoQuality quality, required VideoResolutionFallbackRule fallbackRule}) => From 3d6a9f15e8204d9b9e0b109d16cf7addeaf13dfb Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 19 Mar 2024 13:53:35 -0700 Subject: [PATCH 03/10] Add tests --- .../lib/src/android_camera_camerax.dart | 5 +- .../lib/src/camerax_proxy.dart | 14 +- .../test/android_camera_camerax_test.dart | 96 ++++++---- .../android_camera_camerax_test.mocks.dart | 176 ++++++++++-------- 4 files changed, 170 insertions(+), 121 deletions(-) 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 d12ecfd188b..2e7dc61fe10 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 @@ -1185,9 +1185,8 @@ class AndroidCameraCameraX extends CameraPlatform { final AspectRatioStrategy? aspectRatioStrategy = aspectRatio == null ? null - : AspectRatioStrategy( - preferredAspectRatio: aspectRatio, - fallbackRule: AspectRatioStrategy.fallbackRuleAuto); + : proxy.createAspectRatioStrategy( + aspectRatio, AspectRatioStrategy.fallbackRuleAuto); resolutionStrategy = proxy.createResolutionStrategy( boundSize: boundSize, fallbackRule: fallbackRule); return proxy.createResolutionSelector( diff --git a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart index 6096fc308da..45025bb2979 100644 --- a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart +++ b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart @@ -60,6 +60,7 @@ class CameraXProxy { this.createCaptureRequestOptions = _createAttachedCaptureRequestOptions, this.createMeteringPoint = _createAttachedMeteringPoint, this.createFocusMeteringAction = _createAttachedFocusMeteringAction, + this.createAspectRatioStrategy = _createAttachedAspectRatioStrategy, }); /// Returns a [ProcessCameraProvider] instance. @@ -152,7 +153,7 @@ class CameraXProxy { Camera2CameraControl Function(CameraControl cameraControl) getCamera2CameraControl; - /// Create [CapureRequestOptions] with specified options. + /// Create [CaptureRequestOptions] with specified options. CaptureRequestOptions Function( List<(CaptureRequestKeySupportedType, Object?)> options) createCaptureRequestOptions; @@ -168,6 +169,11 @@ class CameraXProxy { FocusMeteringAction Function(List<(MeteringPoint, int?)> meteringPointInfos, bool? disableAutoCancel) createFocusMeteringAction; + /// Creates an [AspectRatioStrategy] with specified aspect ratio and fallback + /// rule. + AspectRatioStrategy Function(int aspectRatio, int fallbackRule) + createAspectRatioStrategy; + static Future _getProcessCameraProvider() { return ProcessCameraProvider.getInstance(); } @@ -295,4 +301,10 @@ class CameraXProxy { meteringPointInfos: meteringPointInfos, disableAutoCancel: disableAutoCancel); } + + static AspectRatioStrategy _createAttachedAspectRatioStrategy( + int preferredAspectRatio, int fallbackRule) { + return AspectRatioStrategy( + preferredAspectRatio: preferredAspectRatio, fallbackRule: fallbackRule); + } } 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 b8daa14fd12..940a837dbdb 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 @@ -47,7 +47,7 @@ import 'package:camera_android_camerax/src/zoom_state.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/services.dart' show DeviceOrientation, PlatformException, Uint8List; -import 'package:flutter/widgets.dart'; +import 'package:flutter/widgets.dart' show BuildContext, Size, Texture, Widget; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; @@ -57,6 +57,7 @@ import 'test_camerax_library.g.dart'; @GenerateNiceMocks(>[ MockSpec(), + MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -158,7 +159,6 @@ void main() { if (highestAvailable) { return ResolutionStrategy.detachedHighestAvailableStrategy(); } - return ResolutionStrategy.detached( boundSize: boundSize, fallbackRule: fallbackRule); }, @@ -170,16 +170,22 @@ void main() { createFallbackStrategy: ( {required VideoQuality quality, required VideoResolutionFallbackRule fallbackRule}) => - MockFallbackStrategy(), + FallbackStrategy.detached( + quality: quality, fallbackRule: fallbackRule), createQualitySelector: ( {required VideoQuality videoQuality, required FallbackStrategy fallbackStrategy}) => - MockQualitySelector(), + QualitySelector.detached(qualityList: [ + VideoQualityData(quality: videoQuality) + ], fallbackStrategy: fallbackStrategy), createCameraStateObserver: (_) => MockObserver(), requestCameraPermissions: (_) => Future.value(), startListeningForDeviceOrientationChange: (_, __) {}, setPreviewSurfaceProvider: (_) => Future.value( - 3), // 3 is a random Flutter SurfaceTexture ID for testing}, + 3), // 3 is a random Flutter SurfaceTexture ID for testing, + createAspectRatioStrategy: (int aspectRatio, int fallbackRule) => + AspectRatioStrategy.detached( + preferredAspectRatio: aspectRatio, fallbackRule: fallbackRule), ); /// CameraXProxy for testing exposure and focus related controls. @@ -367,6 +373,7 @@ void main() { startListeningForDeviceOrientationChange: (_, __) { startedListeningForDeviceOrientationChanges = true; }, + createAspectRatioStrategy: (_, __) => MockAspectRatioStrategy(), ); when(mockPreview.setSurfaceProvider()) @@ -478,6 +485,7 @@ void main() { Observer.detached(onChanged: onChanged), requestCameraPermissions: (_) => Future.value(), startListeningForDeviceOrientationChange: (_, __) {}, + createAspectRatioStrategy: (_, __) => MockAspectRatioStrategy(), ); when(mockProcessCameraProvider.bindToLifecycle(mockBackCameraSelector, @@ -634,52 +642,63 @@ void main() { await camera.createCamera(testCameraDescription, resolutionPreset, enableAudio: enableAudio); - Size? expectedBoundSize; - ResolutionStrategy? expectedResolutionStrategy; + int? expectedAspectRatio; + AspectRatioStrategy? expectedAspectRatioStrategy; switch (resolutionPreset) { case ResolutionPreset.low: - expectedBoundSize = const Size(320, 240); - case ResolutionPreset.medium: - expectedBoundSize = const Size(720, 480); + expectedAspectRatio = AspectRatio.ratio4To3; case ResolutionPreset.high: - expectedBoundSize = const Size(1280, 720); case ResolutionPreset.veryHigh: - expectedBoundSize = const Size(1920, 1080); case ResolutionPreset.ultraHigh: - expectedBoundSize = const Size(3840, 2160); + expectedAspectRatio = AspectRatio.ratio16To9; + case ResolutionPreset.medium: + // Medium resolution preset uses aspect ratio 3:2 which is unsupported + // by CameraX. case ResolutionPreset.max: - expectedResolutionStrategy = - ResolutionStrategy.detachedHighestAvailableStrategy(); + expectedAspectRatioStrategy = null; } - // We expect the strategy to be the highest available or correspond to the - // expected bound size, with fallback to the closest and highest available - // resolution. - expectedResolutionStrategy ??= ResolutionStrategy.detached( - boundSize: expectedBoundSize, - fallbackRule: ResolutionStrategy.fallbackRuleClosestLowerThenHigher); + expectedAspectRatioStrategy = expectedAspectRatio == null + ? null + : AspectRatioStrategy.detached( + preferredAspectRatio: expectedAspectRatio, + fallbackRule: AspectRatioStrategy.fallbackRuleAuto); + + if (expectedAspectRatio == null) { + expect(camera.preview!.resolutionSelector!.aspectRatioStrategy, isNull); + expect(camera.imageCapture!.resolutionSelector!.aspectRatioStrategy, + isNull); + expect(camera.imageAnalysis!.resolutionSelector!.aspectRatioStrategy, + isNull); + continue; + } - expect(camera.preview!.resolutionSelector!.resolutionStrategy!.boundSize, - equals(expectedResolutionStrategy.boundSize)); + // Check aspect ratio. expect( - camera - .imageCapture!.resolutionSelector!.resolutionStrategy!.boundSize, - equals(expectedResolutionStrategy.boundSize)); + camera.preview!.resolutionSelector!.aspectRatioStrategy! + .preferredAspectRatio, + equals(expectedAspectRatioStrategy!.preferredAspectRatio)); expect( - camera - .imageAnalysis!.resolutionSelector!.resolutionStrategy!.boundSize, - equals(expectedResolutionStrategy.boundSize)); + camera.imageCapture!.resolutionSelector!.aspectRatioStrategy! + .preferredAspectRatio, + equals(expectedAspectRatioStrategy.preferredAspectRatio)); expect( - camera.preview!.resolutionSelector!.resolutionStrategy!.fallbackRule, - equals(expectedResolutionStrategy.fallbackRule)); + camera.imageAnalysis!.resolutionSelector!.aspectRatioStrategy! + .preferredAspectRatio, + equals(expectedAspectRatioStrategy.preferredAspectRatio)); + + // Check fallback rule. expect( - camera.imageCapture!.resolutionSelector!.resolutionStrategy! + camera.preview!.resolutionSelector!.aspectRatioStrategy!.fallbackRule, + equals(expectedAspectRatioStrategy.fallbackRule)); + expect( + camera.imageCapture!.resolutionSelector!.aspectRatioStrategy! .fallbackRule, - equals(expectedResolutionStrategy.fallbackRule)); + equals(expectedAspectRatioStrategy.fallbackRule)); expect( - camera.imageAnalysis!.resolutionSelector!.resolutionStrategy! + camera.imageAnalysis!.resolutionSelector!.aspectRatioStrategy! .fallbackRule, - equals(expectedResolutionStrategy.fallbackRule)); + equals(expectedAspectRatioStrategy.fallbackRule)); } // Test null case. @@ -707,17 +726,13 @@ void main() { final MockProcessCameraProvider mockProcessCameraProvider = MockProcessCameraProvider(); final MockCameraInfo mockCameraInfo = MockCameraInfo(); - final MockPreview mockPreview = MockPreview(); - final MockImageCapture mockImageCapture = MockImageCapture(); - final MockImageAnalysis mockImageAnalysis = MockImageAnalysis(); // Tell plugin to create mock/detached objects for testing createCamera // as needed. camera.proxy = getProxyForTestingResolutionPreset(mockProcessCameraProvider); - when(mockProcessCameraProvider.bindToLifecycle( - any, [mockPreview, mockImageCapture, mockImageAnalysis])) + when(mockProcessCameraProvider.bindToLifecycle(any, any)) .thenAnswer((_) async => mockCamera); when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); when(mockCameraInfo.getCameraState()) @@ -839,6 +854,7 @@ void main() { Observer.detached(onChanged: onChanged), requestCameraPermissions: (_) => Future.value(), startListeningForDeviceOrientationChange: (_, __) {}, + createAspectRatioStrategy: (_, __) => MockAspectRatioStrategy(), ); final CameraInitializedEvent testCameraInitializedEvent = diff --git a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart index 80d76d8339c..141082ad9ac 100644 --- a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart +++ b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart @@ -4,49 +4,50 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i16; -import 'dart:typed_data' as _i31; +import 'dart:typed_data' as _i32; import 'package:camera_android_camerax/src/analyzer.dart' as _i15; +import 'package:camera_android_camerax/src/aspect_ratio_strategy.dart' as _i18; import 'package:camera_android_camerax/src/camera.dart' as _i9; -import 'package:camera_android_camerax/src/camera2_camera_control.dart' as _i22; +import 'package:camera_android_camerax/src/camera2_camera_control.dart' as _i23; import 'package:camera_android_camerax/src/camera_control.dart' as _i3; import 'package:camera_android_camerax/src/camera_info.dart' as _i2; -import 'package:camera_android_camerax/src/camera_selector.dart' as _i24; -import 'package:camera_android_camerax/src/camera_state.dart' as _i18; +import 'package:camera_android_camerax/src/camera_selector.dart' as _i25; +import 'package:camera_android_camerax/src/camera_state.dart' as _i19; import 'package:camera_android_camerax/src/camerax_library.g.dart' as _i7; import 'package:camera_android_camerax/src/capture_request_options.dart' - as _i23; + as _i24; import 'package:camera_android_camerax/src/exposure_state.dart' as _i5; -import 'package:camera_android_camerax/src/fallback_strategy.dart' as _i25; -import 'package:camera_android_camerax/src/focus_metering_action.dart' as _i21; -import 'package:camera_android_camerax/src/focus_metering_result.dart' as _i20; -import 'package:camera_android_camerax/src/image_analysis.dart' as _i26; -import 'package:camera_android_camerax/src/image_capture.dart' as _i27; +import 'package:camera_android_camerax/src/fallback_strategy.dart' as _i26; +import 'package:camera_android_camerax/src/focus_metering_action.dart' as _i22; +import 'package:camera_android_camerax/src/focus_metering_result.dart' as _i21; +import 'package:camera_android_camerax/src/image_analysis.dart' as _i27; +import 'package:camera_android_camerax/src/image_capture.dart' as _i28; import 'package:camera_android_camerax/src/image_proxy.dart' as _i17; import 'package:camera_android_camerax/src/live_data.dart' as _i4; -import 'package:camera_android_camerax/src/observer.dart' as _i30; +import 'package:camera_android_camerax/src/observer.dart' as _i31; import 'package:camera_android_camerax/src/pending_recording.dart' as _i10; -import 'package:camera_android_camerax/src/plane_proxy.dart' as _i29; -import 'package:camera_android_camerax/src/preview.dart' as _i32; +import 'package:camera_android_camerax/src/plane_proxy.dart' as _i30; +import 'package:camera_android_camerax/src/preview.dart' as _i33; import 'package:camera_android_camerax/src/process_camera_provider.dart' - as _i33; -import 'package:camera_android_camerax/src/quality_selector.dart' as _i35; + as _i34; +import 'package:camera_android_camerax/src/quality_selector.dart' as _i36; import 'package:camera_android_camerax/src/recorder.dart' as _i11; import 'package:camera_android_camerax/src/recording.dart' as _i8; -import 'package:camera_android_camerax/src/resolution_selector.dart' as _i36; -import 'package:camera_android_camerax/src/resolution_strategy.dart' as _i37; -import 'package:camera_android_camerax/src/use_case.dart' as _i34; -import 'package:camera_android_camerax/src/video_capture.dart' as _i38; -import 'package:camera_android_camerax/src/zoom_state.dart' as _i19; +import 'package:camera_android_camerax/src/resolution_selector.dart' as _i37; +import 'package:camera_android_camerax/src/resolution_strategy.dart' as _i38; +import 'package:camera_android_camerax/src/use_case.dart' as _i35; +import 'package:camera_android_camerax/src/video_capture.dart' as _i39; +import 'package:camera_android_camerax/src/zoom_state.dart' as _i20; import 'package:camera_platform_interface/camera_platform_interface.dart' as _i6; import 'package:flutter/foundation.dart' as _i14; import 'package:flutter/services.dart' as _i13; import 'package:flutter/widgets.dart' as _i12; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i28; +import 'package:mockito/src/dummies.dart' as _i29; -import 'test_camerax_library.g.dart' as _i39; +import 'test_camerax_library.g.dart' as _i40; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -240,6 +241,27 @@ class MockAnalyzer extends _i1.Mock implements _i15.Analyzer { ) as _i16.Future Function(_i17.ImageProxy)); } +/// A class which mocks [AspectRatioStrategy]. +/// +/// See the documentation for Mockito's code generation for more information. +// ignore: must_be_immutable +class MockAspectRatioStrategy extends _i1.Mock + implements _i18.AspectRatioStrategy { + @override + int get preferredAspectRatio => (super.noSuchMethod( + Invocation.getter(#preferredAspectRatio), + returnValue: 0, + returnValueForMissingStub: 0, + ) as int); + + @override + int get fallbackRule => (super.noSuchMethod( + Invocation.getter(#fallbackRule), + returnValue: 0, + returnValueForMissingStub: 0, + ) as int); +} + /// A class which mocks [Camera]. /// /// See the documentation for Mockito's code generation for more information. @@ -308,14 +330,14 @@ class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { ) as _i16.Future); @override - _i16.Future<_i4.LiveData<_i18.CameraState>> getCameraState() => + _i16.Future<_i4.LiveData<_i19.CameraState>> getCameraState() => (super.noSuchMethod( Invocation.method( #getCameraState, [], ), - returnValue: _i16.Future<_i4.LiveData<_i18.CameraState>>.value( - _FakeLiveData_2<_i18.CameraState>( + returnValue: _i16.Future<_i4.LiveData<_i19.CameraState>>.value( + _FakeLiveData_2<_i19.CameraState>( this, Invocation.method( #getCameraState, @@ -323,15 +345,15 @@ class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { ), )), returnValueForMissingStub: - _i16.Future<_i4.LiveData<_i18.CameraState>>.value( - _FakeLiveData_2<_i18.CameraState>( + _i16.Future<_i4.LiveData<_i19.CameraState>>.value( + _FakeLiveData_2<_i19.CameraState>( this, Invocation.method( #getCameraState, [], ), )), - ) as _i16.Future<_i4.LiveData<_i18.CameraState>>); + ) as _i16.Future<_i4.LiveData<_i19.CameraState>>); @override _i16.Future<_i5.ExposureState> getExposureState() => (super.noSuchMethod( @@ -357,14 +379,14 @@ class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { ) as _i16.Future<_i5.ExposureState>); @override - _i16.Future<_i4.LiveData<_i19.ZoomState>> getZoomState() => + _i16.Future<_i4.LiveData<_i20.ZoomState>> getZoomState() => (super.noSuchMethod( Invocation.method( #getZoomState, [], ), - returnValue: _i16.Future<_i4.LiveData<_i19.ZoomState>>.value( - _FakeLiveData_2<_i19.ZoomState>( + returnValue: _i16.Future<_i4.LiveData<_i20.ZoomState>>.value( + _FakeLiveData_2<_i20.ZoomState>( this, Invocation.method( #getZoomState, @@ -372,15 +394,15 @@ class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { ), )), returnValueForMissingStub: - _i16.Future<_i4.LiveData<_i19.ZoomState>>.value( - _FakeLiveData_2<_i19.ZoomState>( + _i16.Future<_i4.LiveData<_i20.ZoomState>>.value( + _FakeLiveData_2<_i20.ZoomState>( this, Invocation.method( #getZoomState, [], ), )), - ) as _i16.Future<_i4.LiveData<_i19.ZoomState>>); + ) as _i16.Future<_i4.LiveData<_i20.ZoomState>>); } /// A class which mocks [CameraControl]. @@ -409,17 +431,17 @@ class MockCameraControl extends _i1.Mock implements _i3.CameraControl { ) as _i16.Future); @override - _i16.Future<_i20.FocusMeteringResult?> startFocusAndMetering( - _i21.FocusMeteringAction? action) => + _i16.Future<_i21.FocusMeteringResult?> startFocusAndMetering( + _i22.FocusMeteringAction? action) => (super.noSuchMethod( Invocation.method( #startFocusAndMetering, [action], ), - returnValue: _i16.Future<_i20.FocusMeteringResult?>.value(), + returnValue: _i16.Future<_i21.FocusMeteringResult?>.value(), returnValueForMissingStub: - _i16.Future<_i20.FocusMeteringResult?>.value(), - ) as _i16.Future<_i20.FocusMeteringResult?>); + _i16.Future<_i21.FocusMeteringResult?>.value(), + ) as _i16.Future<_i21.FocusMeteringResult?>); @override _i16.Future cancelFocusAndMetering() => (super.noSuchMethod( @@ -448,7 +470,7 @@ class MockCameraControl extends _i1.Mock implements _i3.CameraControl { /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockCamera2CameraControl extends _i1.Mock - implements _i22.Camera2CameraControl { + implements _i23.Camera2CameraControl { @override _i3.CameraControl get cameraControl => (super.noSuchMethod( Invocation.getter(#cameraControl), @@ -464,7 +486,7 @@ class MockCamera2CameraControl extends _i1.Mock @override _i16.Future addCaptureRequestOptions( - _i23.CaptureRequestOptions? captureRequestOptions) => + _i24.CaptureRequestOptions? captureRequestOptions) => (super.noSuchMethod( Invocation.method( #addCaptureRequestOptions, @@ -519,7 +541,7 @@ class MockCameraImageData extends _i1.Mock implements _i6.CameraImageData { /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockCameraSelector extends _i1.Mock implements _i24.CameraSelector { +class MockCameraSelector extends _i1.Mock implements _i25.CameraSelector { @override _i16.Future> filter(List<_i2.CameraInfo>? cameraInfos) => (super.noSuchMethod( @@ -565,7 +587,7 @@ class MockExposureState extends _i1.Mock implements _i5.ExposureState { /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockFallbackStrategy extends _i1.Mock implements _i25.FallbackStrategy { +class MockFallbackStrategy extends _i1.Mock implements _i26.FallbackStrategy { @override _i7.VideoQuality get quality => (super.noSuchMethod( Invocation.getter(#quality), @@ -587,7 +609,7 @@ class MockFallbackStrategy extends _i1.Mock implements _i25.FallbackStrategy { /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockFocusMeteringResult extends _i1.Mock - implements _i20.FocusMeteringResult { + implements _i21.FocusMeteringResult { @override _i16.Future isFocusSuccessful() => (super.noSuchMethod( Invocation.method( @@ -603,7 +625,7 @@ class MockFocusMeteringResult extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockImageAnalysis extends _i1.Mock implements _i26.ImageAnalysis { +class MockImageAnalysis extends _i1.Mock implements _i27.ImageAnalysis { @override _i16.Future setTargetRotation(int? rotation) => (super.noSuchMethod( Invocation.method( @@ -639,7 +661,7 @@ class MockImageAnalysis extends _i1.Mock implements _i26.ImageAnalysis { /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockImageCapture extends _i1.Mock implements _i27.ImageCapture { +class MockImageCapture extends _i1.Mock implements _i28.ImageCapture { @override _i16.Future setTargetRotation(int? rotation) => (super.noSuchMethod( Invocation.method( @@ -666,7 +688,7 @@ class MockImageCapture extends _i1.Mock implements _i27.ImageCapture { #takePicture, [], ), - returnValue: _i16.Future.value(_i28.dummyValue( + returnValue: _i16.Future.value(_i29.dummyValue( this, Invocation.method( #takePicture, @@ -674,7 +696,7 @@ class MockImageCapture extends _i1.Mock implements _i27.ImageCapture { ), )), returnValueForMissingStub: - _i16.Future.value(_i28.dummyValue( + _i16.Future.value(_i29.dummyValue( this, Invocation.method( #takePicture, @@ -711,16 +733,16 @@ class MockImageProxy extends _i1.Mock implements _i17.ImageProxy { ) as int); @override - _i16.Future> getPlanes() => (super.noSuchMethod( + _i16.Future> getPlanes() => (super.noSuchMethod( Invocation.method( #getPlanes, [], ), returnValue: - _i16.Future>.value(<_i29.PlaneProxy>[]), + _i16.Future>.value(<_i30.PlaneProxy>[]), returnValueForMissingStub: - _i16.Future>.value(<_i29.PlaneProxy>[]), - ) as _i16.Future>); + _i16.Future>.value(<_i30.PlaneProxy>[]), + ) as _i16.Future>); @override _i16.Future close() => (super.noSuchMethod( @@ -737,7 +759,7 @@ class MockImageProxy extends _i1.Mock implements _i17.ImageProxy { /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockObserver extends _i1.Mock implements _i30.Observer<_i18.CameraState> { +class MockObserver extends _i1.Mock implements _i31.Observer<_i19.CameraState> { @override void Function(Object) get onChanged => (super.noSuchMethod( Invocation.getter(#onChanged), @@ -788,13 +810,13 @@ class MockPendingRecording extends _i1.Mock implements _i10.PendingRecording { /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockPlaneProxy extends _i1.Mock implements _i29.PlaneProxy { +class MockPlaneProxy extends _i1.Mock implements _i30.PlaneProxy { @override - _i31.Uint8List get buffer => (super.noSuchMethod( + _i32.Uint8List get buffer => (super.noSuchMethod( Invocation.getter(#buffer), - returnValue: _i31.Uint8List(0), - returnValueForMissingStub: _i31.Uint8List(0), - ) as _i31.Uint8List); + returnValue: _i32.Uint8List(0), + returnValueForMissingStub: _i32.Uint8List(0), + ) as _i32.Uint8List); @override int get pixelStride => (super.noSuchMethod( @@ -815,7 +837,7 @@ class MockPlaneProxy extends _i1.Mock implements _i29.PlaneProxy { /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockPreview extends _i1.Mock implements _i32.Preview { +class MockPreview extends _i1.Mock implements _i33.Preview { @override _i16.Future setTargetRotation(int? rotation) => (super.noSuchMethod( Invocation.method( @@ -875,7 +897,7 @@ class MockPreview extends _i1.Mock implements _i32.Preview { /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockProcessCameraProvider extends _i1.Mock - implements _i33.ProcessCameraProvider { + implements _i34.ProcessCameraProvider { @override _i16.Future> getAvailableCameraInfos() => (super.noSuchMethod( @@ -891,8 +913,8 @@ class MockProcessCameraProvider extends _i1.Mock @override _i16.Future<_i9.Camera> bindToLifecycle( - _i24.CameraSelector? cameraSelector, - List<_i34.UseCase>? useCases, + _i25.CameraSelector? cameraSelector, + List<_i35.UseCase>? useCases, ) => (super.noSuchMethod( Invocation.method( @@ -925,7 +947,7 @@ class MockProcessCameraProvider extends _i1.Mock ) as _i16.Future<_i9.Camera>); @override - _i16.Future isBound(_i34.UseCase? useCase) => (super.noSuchMethod( + _i16.Future isBound(_i35.UseCase? useCase) => (super.noSuchMethod( Invocation.method( #isBound, [useCase], @@ -935,7 +957,7 @@ class MockProcessCameraProvider extends _i1.Mock ) as _i16.Future); @override - void unbind(List<_i34.UseCase>? useCases) => super.noSuchMethod( + void unbind(List<_i35.UseCase>? useCases) => super.noSuchMethod( Invocation.method( #unbind, [useCases], @@ -957,7 +979,7 @@ class MockProcessCameraProvider extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockQualitySelector extends _i1.Mock implements _i35.QualitySelector { +class MockQualitySelector extends _i1.Mock implements _i36.QualitySelector { @override List<_i7.VideoQualityData> get qualityList => (super.noSuchMethod( Invocation.getter(#qualityList), @@ -1002,14 +1024,14 @@ class MockRecorder extends _i1.Mock implements _i11.Recorder { /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockResolutionSelector extends _i1.Mock - implements _i36.ResolutionSelector {} + implements _i37.ResolutionSelector {} /// A class which mocks [ResolutionStrategy]. /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockResolutionStrategy extends _i1.Mock - implements _i37.ResolutionStrategy {} + implements _i38.ResolutionStrategy {} /// A class which mocks [Recording]. /// @@ -1061,7 +1083,7 @@ class MockRecording extends _i1.Mock implements _i8.Recording { /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockVideoCapture extends _i1.Mock implements _i38.VideoCapture { +class MockVideoCapture extends _i1.Mock implements _i39.VideoCapture { @override _i16.Future setTargetRotation(int? rotation) => (super.noSuchMethod( Invocation.method( @@ -1284,7 +1306,7 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { /// /// See the documentation for Mockito's code generation for more information. class MockTestInstanceManagerHostApi extends _i1.Mock - implements _i39.TestInstanceManagerHostApi { + implements _i40.TestInstanceManagerHostApi { @override void clear() => super.noSuchMethod( Invocation.method( @@ -1299,7 +1321,7 @@ class MockTestInstanceManagerHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestSystemServicesHostApi extends _i1.Mock - implements _i39.TestSystemServicesHostApi { + implements _i40.TestSystemServicesHostApi { @override _i16.Future<_i7.CameraPermissionsErrorData?> requestCameraPermissions( bool? enableAudio) => @@ -1326,7 +1348,7 @@ class MockTestSystemServicesHostApi extends _i1.Mock suffix, ], ), - returnValue: _i28.dummyValue( + returnValue: _i29.dummyValue( this, Invocation.method( #getTempFilePath, @@ -1336,7 +1358,7 @@ class MockTestSystemServicesHostApi extends _i1.Mock ], ), ), - returnValueForMissingStub: _i28.dummyValue( + returnValueForMissingStub: _i29.dummyValue( this, Invocation.method( #getTempFilePath, @@ -1353,7 +1375,7 @@ class MockTestSystemServicesHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockZoomState extends _i1.Mock implements _i19.ZoomState { +class MockZoomState extends _i1.Mock implements _i20.ZoomState { @override double get minZoomRatio => (super.noSuchMethod( Invocation.getter(#minZoomRatio), @@ -1374,13 +1396,13 @@ class MockZoomState extends _i1.Mock implements _i19.ZoomState { /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockLiveCameraState extends _i1.Mock - implements _i4.LiveData<_i18.CameraState> { + implements _i4.LiveData<_i19.CameraState> { MockLiveCameraState() { _i1.throwOnMissingStub(this); } @override - _i16.Future observe(_i30.Observer<_i18.CameraState>? observer) => + _i16.Future observe(_i31.Observer<_i19.CameraState>? observer) => (super.noSuchMethod( Invocation.method( #observe, @@ -1406,13 +1428,13 @@ class MockLiveCameraState extends _i1.Mock /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockLiveZoomState extends _i1.Mock - implements _i4.LiveData<_i19.ZoomState> { + implements _i4.LiveData<_i20.ZoomState> { MockLiveZoomState() { _i1.throwOnMissingStub(this); } @override - _i16.Future observe(_i30.Observer<_i19.ZoomState>? observer) => + _i16.Future observe(_i31.Observer<_i20.ZoomState>? observer) => (super.noSuchMethod( Invocation.method( #observe, From 02d8bb06f26bf06cbb37ac0d6db63532c15edb98 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 19 Mar 2024 14:45:45 -0700 Subject: [PATCH 04/10] Bump version --- packages/camera/camera_android_camerax/CHANGELOG.md | 4 ++++ packages/camera/camera_android_camerax/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera_android_camerax/CHANGELOG.md b/packages/camera/camera_android_camerax/CHANGELOG.md index 2fd0eb9ed3d..9ea0b8a095c 100644 --- a/packages/camera/camera_android_camerax/CHANGELOG.md +++ b/packages/camera/camera_android_camerax/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.1 + +* Modifies resolution selection logic to use an `AspectRatioStrategy` for all aspect ratios supported by CameraX. + ## 0.6.0 * Implements `setFocusMode`, which makes this plugin reach feature parity with camera_android. diff --git a/packages/camera/camera_android_camerax/pubspec.yaml b/packages/camera/camera_android_camerax/pubspec.yaml index a1a44f06f36..0f4756be1bb 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.6.0 +version: 0.6.1 environment: sdk: ^3.1.0 From 4151936377c22552533a99b028aa4f7e76b16bbc Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:11:00 -0700 Subject: [PATCH 05/10] Update packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart Co-authored-by: Gray Mackall <34871572+gmackall@users.noreply.github.com> --- .../camera/camera_android_camerax/lib/src/camerax_proxy.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart index 45025bb2979..39158cc8606 100644 --- a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart +++ b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart @@ -153,7 +153,7 @@ class CameraXProxy { Camera2CameraControl Function(CameraControl cameraControl) getCamera2CameraControl; - /// Create [CaptureRequestOptions] with specified options. + /// Creates a [CaptureRequestOptions] with specified options. CaptureRequestOptions Function( List<(CaptureRequestKeySupportedType, Object?)> options) createCaptureRequestOptions; From 559df9b92f7ba164dc8bdbcc8d2a7389bb175251 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 26 Mar 2024 10:43:08 -0700 Subject: [PATCH 06/10] Add functionality + java tests --- .../camerax/CameraAndroidCameraxPlugin.java | 2 + .../camerax/GeneratedCameraXLibrary.java | 80 +++++++++++++- .../camerax/ResolutionFilterHostApiImpl.java | 86 +++++++++++++++ .../ResolutionSelectorHostApiImpl.java | 17 ++- .../plugins/camerax/ResolutionFilterTest.java | 79 +++++++++++++ .../camerax/ResolutionSelectorTest.java | 13 ++- .../lib/src/android_camera_camerax.dart | 15 +-- .../lib/src/camerax_library.g.dart | 65 ++++++++++- .../lib/src/camerax_proxy.dart | 21 +++- .../lib/src/resolution_filter.dart | 104 ++++++++++++++++++ .../lib/src/resolution_selector.dart | 16 ++- .../lib/src/zoom_state.dart | 2 +- .../pigeons/camerax_library.dart | 7 ++ .../test/test_camerax_library.g.dart | 74 ++++++++++++- 14 files changed, 558 insertions(+), 23 deletions(-) create mode 100644 packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java create mode 100644 packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java create mode 100644 packages/camera/camera_android_camerax/lib/src/resolution_filter.dart diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java index 6a30074a2f8..d281bbe65a8 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java @@ -134,6 +134,8 @@ public void setUp( binaryMessenger, new FocusMeteringResultHostApiImpl(instanceManager)); meteringPointHostApiImpl = new MeteringPointHostApiImpl(instanceManager); GeneratedCameraXLibrary.MeteringPointHostApi.setup(binaryMessenger, meteringPointHostApiImpl); + GeneratedCameraXLibrary.ResolutionFilterHostApi.setup( + binaryMessenger, new ResolutionFilterHostApiImpl(instanceManager)); } @Override diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java index 75b4a8c276b..fa6be792096 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java @@ -2507,6 +2507,7 @@ public interface ResolutionSelectorHostApi { void create( @NonNull Long identifier, @Nullable Long resolutionStrategyIdentifier, + @Nullable Long resolutionSelectorIdentifier, @Nullable Long aspectRatioStrategyIdentifier); /** The codec used by ResolutionSelectorHostApi. */ @@ -2530,13 +2531,17 @@ static void setup( ArrayList args = (ArrayList) message; Number identifierArg = (Number) args.get(0); Number resolutionStrategyIdentifierArg = (Number) args.get(1); - Number aspectRatioStrategyIdentifierArg = (Number) args.get(2); + Number resolutionSelectorIdentifierArg = (Number) args.get(2); + Number aspectRatioStrategyIdentifierArg = (Number) args.get(3); try { api.create( (identifierArg == null) ? null : identifierArg.longValue(), (resolutionStrategyIdentifierArg == null) ? null : resolutionStrategyIdentifierArg.longValue(), + (resolutionSelectorIdentifierArg == null) + ? null + : resolutionSelectorIdentifierArg.longValue(), (aspectRatioStrategyIdentifierArg == null) ? null : aspectRatioStrategyIdentifierArg.longValue()); @@ -4189,4 +4194,77 @@ public void error(Throwable error) { } } } + + private static class ResolutionFilterHostApiCodec extends StandardMessageCodec { + public static final ResolutionFilterHostApiCodec INSTANCE = new ResolutionFilterHostApiCodec(); + + private ResolutionFilterHostApiCodec() {} + + @Override + protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { + switch (type) { + case (byte) 128: + return ResolutionInfo.fromList((ArrayList) readValue(buffer)); + default: + return super.readValueOfType(type, buffer); + } + } + + @Override + protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { + if (value instanceof ResolutionInfo) { + stream.write(128); + writeValue(stream, ((ResolutionInfo) value).toList()); + } else { + super.writeValue(stream, value); + } + } + } + + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + public interface ResolutionFilterHostApi { + + void createWithOnePreferredSize( + @NonNull Long identifier, @NonNull ResolutionInfo preferredResolution); + + /** The codec used by ResolutionFilterHostApi. */ + static @NonNull MessageCodec getCodec() { + return ResolutionFilterHostApiCodec.INSTANCE; + } + /** + * Sets up an instance of `ResolutionFilterHostApi` to handle messages through the + * `binaryMessenger`. + */ + static void setup( + @NonNull BinaryMessenger binaryMessenger, @Nullable ResolutionFilterHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.ResolutionFilterHostApi.createWithOnePreferredSize", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + Number identifierArg = (Number) args.get(0); + ResolutionInfo preferredResolutionArg = (ResolutionInfo) args.get(1); + try { + api.createWithOnePreferredSize( + (identifierArg == null) ? null : identifierArg.longValue(), + preferredResolutionArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } } diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java new file mode 100644 index 00000000000..abaf1659272 --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java @@ -0,0 +1,86 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.camerax; + +import android.util.Size; +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import androidx.camera.core.resolutionselector.ResolutionFilter; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ResolutionFilterHostApi; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ResolutionInfo; +import java.util.List; + +/** + * Host API implementation for {@link ResolutionFilter}. + * + *

This class handles instantiating and adding native object instances that are attached to a + * Dart instance or handle method calls on the associated native class or an instance of the class. + */ +public class ResolutionFilterHostApiImpl implements ResolutionFilterHostApi { + private final InstanceManager instanceManager; + private final ResolutionFilterProxy proxy; + + /** Proxy for constructor of {@link ResolutionFilter}. */ + @VisibleForTesting + public static class ResolutionFilterProxy { + /** + * Creates an instance of {@link ResolutionFilter} that moves the {@code preferredSize} to the + * front of the list of supported resolutions such that it can be prioritized by CameraX. + */ + @NonNull + public ResolutionFilter createWithOnePreferredSize(@NonNull Size preferredSize) { + return new ResolutionFilter() { + @Override + @NonNull + public List filter(@NonNull List supportedSizes, int rotationDegrees) { + int preferredSizeIndex = supportedSizes.indexOf(preferredSize); + + if (preferredSizeIndex > -1) { + supportedSizes.remove(preferredSizeIndex); + supportedSizes.add(0, preferredSize); + } + + return supportedSizes; + } + }; + } + } + + /** + * Constructs a {@link ResolutionFilterHostApiImpl}. + * + * @param instanceManager maintains instances stored to communicate with attached Dart objects + */ + public ResolutionFilterHostApiImpl(@NonNull InstanceManager instanceManager) { + this(instanceManager, new ResolutionFilterProxy()); + } + + /** + * Constructs a {@link ResolutionFilterHostApiImpl}. + * + * @param instanceManager maintains instances stored to communicate with attached Dart objects + * @param proxy proxy for constructor of {@link ResolutionFilter} + */ + @VisibleForTesting + ResolutionFilterHostApiImpl( + @NonNull InstanceManager instanceManager, @NonNull ResolutionFilterProxy proxy) { + this.instanceManager = instanceManager; + this.proxy = proxy; + } + + /** + * Creates a {@link ResolutionFilter} that prioritizes the specified {@code preferredResolution} + * over all other resolutions. + */ + @Override + public void createWithOnePreferredSize( + @NonNull Long identifier, @NonNull ResolutionInfo preferredResolution) { + Size preferredSize = + new Size( + preferredResolution.getWidth().intValue(), preferredResolution.getHeight().intValue()); + instanceManager.addDartCreatedInstance( + proxy.createWithOnePreferredSize(preferredSize), identifier); + } +} diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionSelectorHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionSelectorHostApiImpl.java index 4aa11cd593f..96cb1f3ad9b 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionSelectorHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionSelectorHostApiImpl.java @@ -8,6 +8,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.camera.core.resolutionselector.AspectRatioStrategy; +import androidx.camera.core.resolutionselector.ResolutionFilter; import androidx.camera.core.resolutionselector.ResolutionSelector; import androidx.camera.core.resolutionselector.ResolutionStrategy; import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ResolutionSelectorHostApi; @@ -30,11 +31,15 @@ public static class ResolutionSelectorProxy { @NonNull public ResolutionSelector create( @Nullable ResolutionStrategy resolutionStrategy, - @Nullable AspectRatioStrategy aspectRatioStrategy) { + @Nullable AspectRatioStrategy aspectRatioStrategy, + @Nullable ResolutionFilter resolutionFilter) { final ResolutionSelector.Builder builder = new ResolutionSelector.Builder(); if (resolutionStrategy != null) { builder.setResolutionStrategy(resolutionStrategy); } + if (resolutionFilter != null) { + builder.setResolutionFilter(resolutionFilter); + } if (aspectRatioStrategy != null) { builder.setAspectRatioStrategy(aspectRatioStrategy); } @@ -65,13 +70,14 @@ public ResolutionSelectorHostApiImpl(@NonNull InstanceManager instanceManager) { } /** - * Creates a {@link ResolutionSelector} instance with the {@link ResolutionStrategy} and {@link - * AspectRatio} that have the identifiers specified if provided. + * Creates a {@link ResolutionSelector} instance with the {@link ResolutionStrategy}, {@link + * ResolutionFilter}, and {@link AspectRatio} that have the identifiers specified if provided. */ @Override public void create( @NonNull Long identifier, @Nullable Long resolutionStrategyIdentifier, + @Nullable Long resolutionFilterIdentifier, @Nullable Long aspectRatioStrategyIdentifier) { instanceManager.addDartCreatedInstance( proxy.create( @@ -81,7 +87,10 @@ public void create( aspectRatioStrategyIdentifier == null ? null : Objects.requireNonNull( - instanceManager.getInstance(aspectRatioStrategyIdentifier))), + instanceManager.getInstance(aspectRatioStrategyIdentifier)), + resolutionFilterIdentifier == null + ? null + : Objects.requireNonNull(instanceManager.getInstance(resolutionFilterIdentifier))), identifier); } } diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java new file mode 100644 index 00000000000..8fe3d3538f9 --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java @@ -0,0 +1,79 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.camerax; + +import static org.junit.Assert.assertEquals; + +import android.util.Size; +import androidx.camera.core.resolutionselector.ResolutionFilter; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ResolutionInfo; +import java.util.ArrayList; +import java.util.List; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class ResolutionFilterTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + @Mock public ResolutionFilter mockResolutionFilter; + + InstanceManager instanceManager; + + @Before + public void setUp() { + instanceManager = InstanceManager.create(identifier -> {}); + } + + @After + public void tearDown() { + instanceManager.stopFinalizationListener(); + } + + @Test + public void hostApiCreateWithOnePreferredSize_createsExpectedResolutionFilterInstance() { + final android.util.Size lala = new android.util.Size(720, 480); + final ResolutionFilterHostApiImpl hostApi = new ResolutionFilterHostApiImpl(instanceManager); + final long instanceIdentifier = 50; + final long preferredResolutionWidth = 20; + final long preferredResolutionHeight = 80; + final ResolutionInfo preferredResolution = + new ResolutionInfo.Builder() + .setWidth(preferredResolutionWidth) + .setHeight(preferredResolutionHeight) + .build(); + + hostApi.createWithOnePreferredSize(instanceIdentifier, preferredResolution); + + // Test instance filters supported resolutions as expected. + final ResolutionFilter resolutionFilter = instanceManager.getInstance(instanceIdentifier); + final Size fakeSupportedSize1 = new Size(720, 480); + final Size fakeSupportedSize2 = new Size(20, 80); + final Size fakeSupportedSize3 = new Size(2, 8); + final Size preferredSize = + new Size((int) preferredResolutionWidth, (int) preferredResolutionHeight); + + final ArrayList fakeSupportedSizes = new ArrayList(); + fakeSupportedSizes.add(fakeSupportedSize1); + fakeSupportedSizes.add(fakeSupportedSize2); + fakeSupportedSizes.add(preferredSize); + fakeSupportedSizes.add(fakeSupportedSize3); + + // Test case where preferred resolution is supported. + List filteredSizes = resolutionFilter.filter(fakeSupportedSizes, 90); + assertEquals(filteredSizes.get(0), preferredSize); + + // Test case where preferred resolution is not supported. + fakeSupportedSizes.remove(0); + filteredSizes = resolutionFilter.filter(fakeSupportedSizes, 90); + assertEquals(filteredSizes, fakeSupportedSizes); + } +} diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionSelectorTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionSelectorTest.java index f323e4706c9..a42887ea1b0 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionSelectorTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionSelectorTest.java @@ -9,6 +9,7 @@ import static org.mockito.Mockito.when; import androidx.camera.core.resolutionselector.AspectRatioStrategy; +import androidx.camera.core.resolutionselector.ResolutionFilter; import androidx.camera.core.resolutionselector.ResolutionSelector; import androidx.camera.core.resolutionselector.ResolutionStrategy; import org.junit.After; @@ -42,17 +43,25 @@ public void hostApiCreate_createsExpectedResolutionSelectorInstance() { final long resolutionStrategyIdentifier = 14; instanceManager.addDartCreatedInstance(mockResolutionStrategy, resolutionStrategyIdentifier); + final ResolutionFilter mockResolutionFilter = mock(ResolutionFilter.class); + final long resolutionFilterIdentifier = 33; + instanceManager.addDartCreatedInstance(mockResolutionFilter, resolutionFilterIdentifier); + final AspectRatioStrategy mockAspectRatioStrategy = mock(AspectRatioStrategy.class); final long aspectRatioStrategyIdentifier = 15; instanceManager.addDartCreatedInstance(mockAspectRatioStrategy, aspectRatioStrategyIdentifier); - when(mockProxy.create(mockResolutionStrategy, mockAspectRatioStrategy)) + when(mockProxy.create(mockResolutionStrategy, mockAspectRatioStrategy, mockResolutionFilter)) .thenReturn(mockResolutionSelector); final ResolutionSelectorHostApiImpl hostApi = new ResolutionSelectorHostApiImpl(instanceManager, mockProxy); final long instanceIdentifier = 0; - hostApi.create(instanceIdentifier, resolutionStrategyIdentifier, aspectRatioStrategyIdentifier); + hostApi.create( + instanceIdentifier, + resolutionStrategyIdentifier, + resolutionFilterIdentifier, + aspectRatioStrategyIdentifier); assertEquals(instanceManager.getInstance(instanceIdentifier), mockResolutionSelector); } 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 2e7dc61fe10..19aaea83fa3 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 @@ -42,6 +42,7 @@ import 'process_camera_provider.dart'; import 'quality_selector.dart'; import 'recorder.dart'; import 'recording.dart'; +import 'resolution_filter.dart'; import 'resolution_selector.dart'; import 'resolution_strategy.dart'; import 'surface.dart'; @@ -1159,8 +1160,6 @@ class AndroidCameraCameraX extends CameraPlatform { boundSize = const Size(320, 240); aspectRatio = AspectRatio.ratio4To3; case ResolutionPreset.medium: - // TODO(camsim99): Handle the 3:2 aspect ratio case: - // https://github.com/flutter/flutter/issues/144363. boundSize = const Size(720, 480); case ResolutionPreset.high: boundSize = const Size(1280, 720); @@ -1175,22 +1174,24 @@ class AndroidCameraCameraX extends CameraPlatform { // Automatically set strategy to choose highest available. resolutionStrategy = proxy.createResolutionStrategy(highestAvailable: true); - return proxy.createResolutionSelector( - resolutionStrategy, /* AspectRatioStrategy */ null); + return proxy.createResolutionSelector(resolutionStrategy, + /* ResolutionFilter */ null, /* AspectRatioStrategy */ null); case null: // If no preset is specified, default to CameraX's default behavior // for each UseCase. return null; } + resolutionStrategy = proxy.createResolutionStrategy( + boundSize: boundSize, fallbackRule: fallbackRule); + final ResolutionFilter resolutionFilter = + proxy.createResolutionFilterWithOnePreferredSize(boundSize); final AspectRatioStrategy? aspectRatioStrategy = aspectRatio == null ? null : proxy.createAspectRatioStrategy( aspectRatio, AspectRatioStrategy.fallbackRuleAuto); - resolutionStrategy = proxy.createResolutionStrategy( - boundSize: boundSize, fallbackRule: fallbackRule); return proxy.createResolutionSelector( - resolutionStrategy, aspectRatioStrategy); + resolutionStrategy, resolutionFilter, aspectRatioStrategy); } /// Returns the [QualitySelector] that maps to the specified resolution diff --git a/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart b/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart index 78c167bc4a1..ac66dfd0ae7 100644 --- a/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart +++ b/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart @@ -1914,7 +1914,10 @@ class ResolutionSelectorHostApi { static const MessageCodec codec = StandardMessageCodec(); - Future create(int arg_identifier, int? arg_resolutionStrategyIdentifier, + Future create( + int arg_identifier, + int? arg_resolutionStrategyIdentifier, + int? arg_resolutionSelectorIdentifier, int? arg_aspectRatioStrategyIdentifier) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.ResolutionSelectorHostApi.create', codec, @@ -1922,6 +1925,7 @@ class ResolutionSelectorHostApi { final List? replyList = await channel.send([ arg_identifier, arg_resolutionStrategyIdentifier, + arg_resolutionSelectorIdentifier, arg_aspectRatioStrategyIdentifier ]) as List?; if (replyList == null) { @@ -3340,3 +3344,62 @@ class Camera2CameraControlHostApi { } } } + +class _ResolutionFilterHostApiCodec extends StandardMessageCodec { + const _ResolutionFilterHostApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is ResolutionInfo) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return ResolutionInfo.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class ResolutionFilterHostApi { + /// Constructor for [ResolutionFilterHostApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + ResolutionFilterHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _ResolutionFilterHostApiCodec(); + + Future createWithOnePreferredSize( + int arg_identifier, ResolutionInfo arg_preferredResolution) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.ResolutionFilterHostApi.createWithOnePreferredSize', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_identifier, arg_preferredResolution]) + as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } +} diff --git a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart index 45025bb2979..dea96f163e6 100644 --- a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart +++ b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart @@ -25,6 +25,7 @@ import 'preview.dart'; import 'process_camera_provider.dart'; import 'quality_selector.dart'; import 'recorder.dart'; +import 'resolution_filter.dart'; import 'resolution_selector.dart'; import 'resolution_strategy.dart'; import 'system_services.dart'; @@ -61,6 +62,8 @@ class CameraXProxy { this.createMeteringPoint = _createAttachedMeteringPoint, this.createFocusMeteringAction = _createAttachedFocusMeteringAction, this.createAspectRatioStrategy = _createAttachedAspectRatioStrategy, + this.createResolutionFilterWithOnePreferredSize = + _createAttachedResolutionFilterWithOnePreferredSize, }); /// Returns a [ProcessCameraProvider] instance. @@ -117,8 +120,10 @@ class CameraXProxy { int? fallbackRule}) createResolutionStrategy; /// Returns a [ResolutionSelector] configured with the specified - /// [ResolutionStrategy] and [AspectRatioStrategy]. - ResolutionSelector Function(ResolutionStrategy resolutionStrategy, + /// [ResolutionStrategy], [ResolutionFilter], and [AspectRatioStrategy]. + ResolutionSelector Function( + ResolutionStrategy resolutionStrategy, + ResolutionFilter? resolutionFilter, AspectRatioStrategy? aspectRatioStrategy) createResolutionSelector; /// Returns a [FallbackStrategy] configured with the specified [VideoQuality] @@ -174,6 +179,10 @@ class CameraXProxy { AspectRatioStrategy Function(int aspectRatio, int fallbackRule) createAspectRatioStrategy; + /// Creates [ResolutionFilter] that prioritizes specified resolution. + ResolutionFilter Function(Size preferredResolution) + createResolutionFilterWithOnePreferredSize; + static Future _getProcessCameraProvider() { return ProcessCameraProvider.getInstance(); } @@ -242,9 +251,11 @@ class CameraXProxy { static ResolutionSelector _createAttachedResolutionSelector( ResolutionStrategy resolutionStrategy, + ResolutionFilter? resolutionFilter, AspectRatioStrategy? aspectRatioStrategy) { return ResolutionSelector( resolutionStrategy: resolutionStrategy, + resolutionFilter: resolutionFilter, aspectRatioStrategy: aspectRatioStrategy); } @@ -307,4 +318,10 @@ class CameraXProxy { return AspectRatioStrategy( preferredAspectRatio: preferredAspectRatio, fallbackRule: fallbackRule); } + + static ResolutionFilter _createAttachedResolutionFilterWithOnePreferredSize( + Size preferredSize) { + return ResolutionFilter.onePreferredSize( + preferredResolution: preferredSize); + } } diff --git a/packages/camera/camera_android_camerax/lib/src/resolution_filter.dart b/packages/camera/camera_android_camerax/lib/src/resolution_filter.dart new file mode 100644 index 00000000000..bfec288356a --- /dev/null +++ b/packages/camera/camera_android_camerax/lib/src/resolution_filter.dart @@ -0,0 +1,104 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:meta/meta.dart' show immutable; + +import 'camerax_library.g.dart'; +import 'instance_manager.dart'; +import 'java_object.dart'; + +/// Filter/sorter for applications to specify preferred resolutions. +/// +/// This is an indirect wrapping of the native Android `ResolutionFilter`, +/// which is an interface that requires a synchronous response, which is not +/// possible through pigeon. Thus, constructing a [ResolutionFilter] will create +/// a native `ResolutionFilter` with the characteristics as described below. If +/// these constructors do not meet your needs, feel free to add a new +/// constructor; see CONTRIBUTING.MD for more information on how to do so. +/// +/// See https://developer.android.com/reference/androidx/camera/core/ResolutionFilter/ResolutionFilter. +@immutable +class ResolutionFilter extends JavaObject { + /// Construct a [ResolutionFilter]. + /// + /// Because this is an indirect wrapping of the native `ResolutionFilter`, + /// this will construct a filter that will only prioritize the specified + /// [preferredResolution] over the other resolutions, whose order of + /// preference (according to CameraX) will remain the same. + ResolutionFilter.onePreferredSize({ + required this.preferredResolution, + super.binaryMessenger, + super.instanceManager, + }) : _api = _ResolutionFilterHostApiImpl( + instanceManager: instanceManager, + binaryMessenger: binaryMessenger, + ), + super.detached() { + _api.createWithOnePreferredSizeFromInstances(this, preferredResolution); + } + + /// Instantiates a [ResolutionFilter.onePreferredSize] that is not + /// automatically attached to a native object. + ResolutionFilter.onePreferredSizeDetached({ + required this.preferredResolution, + super.binaryMessenger, + super.instanceManager, + }) : _api = _ResolutionFilterHostApiImpl( + instanceManager: instanceManager, + binaryMessenger: binaryMessenger, + ), + super.detached(); + + final _ResolutionFilterHostApiImpl _api; + + /// The resolution for the filter to prioritize. + final Size preferredResolution; +} + +/// Host API implementation of [ResolutionFilter]. +class _ResolutionFilterHostApiImpl extends ResolutionFilterHostApi { + /// Constructs an [_ResolutionFilterHostApiImpl]. + /// + /// If [binaryMessenger] is null, the default [BinaryMessenger] will be used, + /// which routes to the host platform. + /// + /// An [instanceManager] is typically passed when a copy of an instance + /// contained by an [InstanceManager] is being created. If left null, it + /// will default to the global instance defined in [JavaObject]. + _ResolutionFilterHostApiImpl({ + this.binaryMessenger, + InstanceManager? instanceManager, + }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager, + super(binaryMessenger: binaryMessenger); + + /// Receives binary data across the Flutter platform barrier. + final BinaryMessenger? binaryMessenger; + + /// Maintains instances stored to communicate with native language objects. + final InstanceManager instanceManager; + + /// Creates a [ResolutionFilter] on the native side that will prioritize + /// the specified [preferredResolution]. + Future createWithOnePreferredSizeFromInstances( + ResolutionFilter instance, + Size preferredResolution, + ) { + return createWithOnePreferredSize( + instanceManager.addDartCreatedInstance( + instance, + onCopy: (ResolutionFilter original) => + ResolutionFilter.onePreferredSizeDetached( + preferredResolution: original.preferredResolution, + binaryMessenger: binaryMessenger, + instanceManager: instanceManager, + ), + ), + ResolutionInfo( + width: preferredResolution.width.toInt(), + height: preferredResolution.height.toInt(), + ), + ); + } +} diff --git a/packages/camera/camera_android_camerax/lib/src/resolution_selector.dart b/packages/camera/camera_android_camerax/lib/src/resolution_selector.dart index 74191724e5c..3017daab811 100644 --- a/packages/camera/camera_android_camerax/lib/src/resolution_selector.dart +++ b/packages/camera/camera_android_camerax/lib/src/resolution_selector.dart @@ -9,6 +9,7 @@ import 'aspect_ratio_strategy.dart'; import 'camerax_library.g.dart'; import 'instance_manager.dart'; import 'java_object.dart'; +import 'resolution_filter.dart'; import 'resolution_strategy.dart'; /// A set of requirements and priorities used to select a resolution for a @@ -20,6 +21,7 @@ class ResolutionSelector extends JavaObject { /// Construct a [ResolutionSelector]. ResolutionSelector({ this.resolutionStrategy, + this.resolutionFilter, this.aspectRatioStrategy, super.binaryMessenger, super.instanceManager, @@ -28,7 +30,8 @@ class ResolutionSelector extends JavaObject { binaryMessenger: binaryMessenger, ), super.detached() { - _api.createFromInstances(this, resolutionStrategy, aspectRatioStrategy); + _api.createFromInstances( + this, resolutionStrategy, resolutionFilter, aspectRatioStrategy); } /// Instantiates a [ResolutionSelector] without creating and attaching to an @@ -38,6 +41,7 @@ class ResolutionSelector extends JavaObject { /// library or to create a copy for an [InstanceManager]. ResolutionSelector.detached({ this.resolutionStrategy, + this.resolutionFilter, this.aspectRatioStrategy, super.binaryMessenger, super.instanceManager, @@ -53,6 +57,9 @@ class ResolutionSelector extends JavaObject { /// image. final ResolutionStrategy? resolutionStrategy; + /// Filter for CameraX to automatically select a desirable resolution. + final ResolutionFilter? resolutionFilter; + /// Determines how the UseCase will choose the aspect ratio of the captured /// image. final AspectRatioStrategy? aspectRatioStrategy; @@ -81,10 +88,12 @@ class _ResolutionSelectorHostApiImpl extends ResolutionSelectorHostApi { final InstanceManager instanceManager; /// Creates a [ResolutionSelector] on the native side with the - /// [ResolutionStrategy] and [AspectRatioStrategy] if specified. + /// [ResolutionStrategy], [ResolutionFilter], and [AspectRatioStrategy] if + /// specified. Future createFromInstances( ResolutionSelector instance, ResolutionStrategy? resolutionStrategy, + ResolutionFilter? resolutionFilter, AspectRatioStrategy? aspectRatioStrategy, ) { return create( @@ -100,6 +109,9 @@ class _ResolutionSelectorHostApiImpl extends ResolutionSelectorHostApi { resolutionStrategy == null ? null : instanceManager.getIdentifier(resolutionStrategy)!, + resolutionFilter == null + ? null + : instanceManager.getIdentifier(resolutionFilter)!, aspectRatioStrategy == null ? null : instanceManager.getIdentifier(aspectRatioStrategy)!, diff --git a/packages/camera/camera_android_camerax/lib/src/zoom_state.dart b/packages/camera/camera_android_camerax/lib/src/zoom_state.dart index 4c93d41e024..6fe5321389b 100644 --- a/packages/camera/camera_android_camerax/lib/src/zoom_state.dart +++ b/packages/camera/camera_android_camerax/lib/src/zoom_state.dart @@ -15,7 +15,7 @@ import 'java_object.dart'; /// See https://developer.android.com/reference/androidx/camera/core/ZoomState. @immutable class ZoomState extends JavaObject { - /// Constructs a [CameraInfo] that is not automatically attached to a native object. + /// Constructs a [ZoomState] that is not automatically attached to a native object. ZoomState.detached( {super.binaryMessenger, super.instanceManager, diff --git a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart index 103c260c25c..4ee51bcb0fa 100644 --- a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart +++ b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart @@ -366,6 +366,7 @@ abstract class ResolutionSelectorHostApi { void create( int identifier, int? resolutionStrategyIdentifier, + int? resolutionSelectorIdentifier, int? aspectRatioStrategyIdentifier, ); } @@ -536,3 +537,9 @@ abstract class Camera2CameraControlHostApi { void addCaptureRequestOptions( int identifier, int captureRequestOptionsIdentifier); } + +@HostApi(dartHostTestHandler: 'ResolutionFilterHostApi') +abstract class ResolutionFilterHostApi { + void createWithOnePreferredSize( + int identifier, ResolutionInfo preferredResolution); +} diff --git a/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart b/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart index b69825928dd..94aa71cff26 100644 --- a/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart +++ b/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart @@ -1321,7 +1321,7 @@ abstract class TestResolutionSelectorHostApi { static const MessageCodec codec = StandardMessageCodec(); void create(int identifier, int? resolutionStrategyIdentifier, - int? aspectRatioStrategyIdentifier); + int? resolutionSelectorIdentifier, int? aspectRatioStrategyIdentifier); static void setup(TestResolutionSelectorHostApi? api, {BinaryMessenger? binaryMessenger}) { @@ -1343,8 +1343,12 @@ abstract class TestResolutionSelectorHostApi { assert(arg_identifier != null, 'Argument for dev.flutter.pigeon.ResolutionSelectorHostApi.create was null, expected non-null int.'); final int? arg_resolutionStrategyIdentifier = (args[1] as int?); - final int? arg_aspectRatioStrategyIdentifier = (args[2] as int?); - api.create(arg_identifier!, arg_resolutionStrategyIdentifier, + final int? arg_resolutionSelectorIdentifier = (args[2] as int?); + final int? arg_aspectRatioStrategyIdentifier = (args[3] as int?); + api.create( + arg_identifier!, + arg_resolutionStrategyIdentifier, + arg_resolutionSelectorIdentifier, arg_aspectRatioStrategyIdentifier); return []; }); @@ -2359,3 +2363,67 @@ abstract class TestCamera2CameraControlHostApi { } } } + +class _ResolutionFilterHostApiCodec extends StandardMessageCodec { + const _ResolutionFilterHostApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is ResolutionInfo) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return ResolutionInfo.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +abstract class ResolutionFilterHostApi { + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => + TestDefaultBinaryMessengerBinding.instance; + static const MessageCodec codec = _ResolutionFilterHostApiCodec(); + + void createWithOnePreferredSize( + int identifier, ResolutionInfo preferredResolution); + + static void setup(ResolutionFilterHostApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.ResolutionFilterHostApi.createWithOnePreferredSize', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.ResolutionFilterHostApi.createWithOnePreferredSize was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.ResolutionFilterHostApi.createWithOnePreferredSize was null, expected non-null int.'); + final ResolutionInfo? arg_preferredResolution = + (args[1] as ResolutionInfo?); + assert(arg_preferredResolution != null, + 'Argument for dev.flutter.pigeon.ResolutionFilterHostApi.createWithOnePreferredSize was null, expected non-null ResolutionInfo.'); + api.createWithOnePreferredSize( + arg_identifier!, arg_preferredResolution!); + return []; + }); + } + } + } +} From 67a324e8707ac95433d247116494f7749431a560 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 26 Mar 2024 11:20:32 -0700 Subject: [PATCH 07/10] Add dart tests --- .../pigeons/camerax_library.dart | 2 +- .../test/android_camera_camerax_test.dart | 101 ++- .../android_camera_camerax_test.mocks.dart | 595 +++++++++--------- .../test/resolution_filter_test.dart | 91 +++ .../test/resolution_filter_test.mocks.dart | 67 ++ .../test/resolution_selector_test.dart | 26 +- .../test/resolution_selector_test.mocks.dart | 48 +- .../test/test_camerax_library.g.dart | 11 +- 8 files changed, 637 insertions(+), 304 deletions(-) create mode 100644 packages/camera/camera_android_camerax/test/resolution_filter_test.dart create mode 100644 packages/camera/camera_android_camerax/test/resolution_filter_test.mocks.dart diff --git a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart index 4ee51bcb0fa..18741904a8d 100644 --- a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart +++ b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart @@ -538,7 +538,7 @@ abstract class Camera2CameraControlHostApi { int identifier, int captureRequestOptionsIdentifier); } -@HostApi(dartHostTestHandler: 'ResolutionFilterHostApi') +@HostApi(dartHostTestHandler: 'TestResolutionFilterHostApi') abstract class ResolutionFilterHostApi { void createWithOnePreferredSize( int identifier, ResolutionInfo preferredResolution); 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 940a837dbdb..f08a2e02ad4 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 @@ -37,6 +37,7 @@ import 'package:camera_android_camerax/src/process_camera_provider.dart'; import 'package:camera_android_camerax/src/quality_selector.dart'; import 'package:camera_android_camerax/src/recorder.dart'; import 'package:camera_android_camerax/src/recording.dart'; +import 'package:camera_android_camerax/src/resolution_filter.dart'; import 'package:camera_android_camerax/src/resolution_selector.dart'; import 'package:camera_android_camerax/src/resolution_strategy.dart'; import 'package:camera_android_camerax/src/surface.dart'; @@ -77,6 +78,7 @@ import 'test_camerax_library.g.dart'; MockSpec(), MockSpec(), MockSpec(), + MockSpec(), MockSpec(), MockSpec(), MockSpec(), @@ -163,9 +165,11 @@ void main() { boundSize: boundSize, fallbackRule: fallbackRule); }, createResolutionSelector: (ResolutionStrategy resolutionStrategy, + ResolutionFilter? resolutionFilter, AspectRatioStrategy? aspectRatioStrategy) => ResolutionSelector.detached( resolutionStrategy: resolutionStrategy, + resolutionFilter: resolutionFilter, aspectRatioStrategy: aspectRatioStrategy), createFallbackStrategy: ( {required VideoQuality quality, @@ -186,6 +190,10 @@ void main() { createAspectRatioStrategy: (int aspectRatio, int fallbackRule) => AspectRatioStrategy.detached( preferredAspectRatio: aspectRatio, fallbackRule: fallbackRule), + createResolutionFilterWithOnePreferredSize: + (Size preferredResolution) => + ResolutionFilter.onePreferredSizeDetached( + preferredResolution: preferredResolution), ); /// CameraXProxy for testing exposure and focus related controls. @@ -355,7 +363,7 @@ void main() { Size? boundSize, int? fallbackRule}) => MockResolutionStrategy(), - createResolutionSelector: (_, __) => MockResolutionSelector(), + createResolutionSelector: (_, __, ___) => MockResolutionSelector(), createFallbackStrategy: ( {required VideoQuality quality, required VideoResolutionFallbackRule fallbackRule}) => @@ -374,6 +382,7 @@ void main() { startedListeningForDeviceOrientationChanges = true; }, createAspectRatioStrategy: (_, __) => MockAspectRatioStrategy(), + createResolutionFilterWithOnePreferredSize: (_) => MockResolutionFilter(), ); when(mockPreview.setSurfaceProvider()) @@ -472,7 +481,7 @@ void main() { Size? boundSize, int? fallbackRule}) => MockResolutionStrategy(), - createResolutionSelector: (_, __) => MockResolutionSelector(), + createResolutionSelector: (_, __, ___) => MockResolutionSelector(), createFallbackStrategy: ( {required VideoQuality quality, required VideoResolutionFallbackRule fallbackRule}) => @@ -486,6 +495,7 @@ void main() { requestCameraPermissions: (_) => Future.value(), startListeningForDeviceOrientationChange: (_, __) {}, createAspectRatioStrategy: (_, __) => MockAspectRatioStrategy(), + createResolutionFilterWithOnePreferredSize: (_) => MockResolutionFilter(), ); when(mockProcessCameraProvider.bindToLifecycle(mockBackCameraSelector, @@ -517,7 +527,7 @@ void main() { }); test( - 'createCamera properly sets preset resolution for non-video capture use cases', + 'createCamera properly sets preset resolution selection strategy for non-video capture use cases', () async { final AndroidCameraCameraX camera = AndroidCameraCameraX(); const CameraLensDirection testLensDirection = CameraLensDirection.back; @@ -607,6 +617,88 @@ void main() { expect(camera.imageAnalysis!.resolutionSelector, isNull); }); + test( + 'createCamera properly sets filter for resolution preset for non-video capture use cases', + () async { + final AndroidCameraCameraX camera = AndroidCameraCameraX(); + const CameraLensDirection testLensDirection = CameraLensDirection.front; + const int testSensorOrientation = 180; + const CameraDescription testCameraDescription = CameraDescription( + name: 'cameraName', + lensDirection: testLensDirection, + sensorOrientation: testSensorOrientation); + const bool enableAudio = true; + final MockCamera mockCamera = MockCamera(); + + // Mock/Detached objects for (typically attached) objects created by + // createCamera. + final MockProcessCameraProvider mockProcessCameraProvider = + MockProcessCameraProvider(); + final MockCameraInfo mockCameraInfo = MockCameraInfo(); + + // Tell plugin to create mock/detached objects for testing createCamera + // as needed. + camera.proxy = + getProxyForTestingResolutionPreset(mockProcessCameraProvider); + + when(mockProcessCameraProvider.bindToLifecycle(any, any)) + .thenAnswer((_) async => mockCamera); + when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); + when(mockCameraInfo.getCameraState()) + .thenAnswer((_) async => MockLiveCameraState()); + camera.processCameraProvider = mockProcessCameraProvider; + + // Test non-null resolution presets. + for (final ResolutionPreset resolutionPreset in ResolutionPreset.values) { + await camera.createCamera(testCameraDescription, resolutionPreset, + enableAudio: enableAudio); + + Size? expectedPreferredResolution; + switch (resolutionPreset) { + case ResolutionPreset.low: + expectedPreferredResolution = const Size(320, 240); + case ResolutionPreset.medium: + expectedPreferredResolution = const Size(720, 480); + case ResolutionPreset.high: + expectedPreferredResolution = const Size(1280, 720); + case ResolutionPreset.veryHigh: + expectedPreferredResolution = const Size(1920, 1080); + case ResolutionPreset.ultraHigh: + expectedPreferredResolution = const Size(3840, 2160); + case ResolutionPreset.max: + expectedPreferredResolution = null; + } + + if (expectedPreferredResolution == null) { + expect(camera.preview!.resolutionSelector!.resolutionFilter, isNull); + expect( + camera.imageCapture!.resolutionSelector!.resolutionFilter, isNull); + expect( + camera.imageAnalysis!.resolutionSelector!.resolutionFilter, isNull); + continue; + } + + expect( + camera.preview!.resolutionSelector!.resolutionFilter! + .preferredResolution, + equals(expectedPreferredResolution)); + expect( + camera + .imageCapture!.resolutionSelector!.resolutionStrategy!.boundSize, + equals(expectedPreferredResolution)); + expect( + camera + .imageAnalysis!.resolutionSelector!.resolutionStrategy!.boundSize, + equals(expectedPreferredResolution)); + } + + // Test null case. + await camera.createCamera(testCameraDescription, null); + expect(camera.preview!.resolutionSelector, isNull); + expect(camera.imageCapture!.resolutionSelector, isNull); + expect(camera.imageAnalysis!.resolutionSelector, isNull); + }); + test( 'createCamera properly sets aspect ratio based on preset resolution for non-video capture use cases', () async { @@ -841,7 +933,7 @@ void main() { Size? boundSize, int? fallbackRule}) => MockResolutionStrategy(), - createResolutionSelector: (_, __) => MockResolutionSelector(), + createResolutionSelector: (_, __, ___) => MockResolutionSelector(), createFallbackStrategy: ( {required VideoQuality quality, required VideoResolutionFallbackRule fallbackRule}) => @@ -855,6 +947,7 @@ void main() { requestCameraPermissions: (_) => Future.value(), startListeningForDeviceOrientationChange: (_, __) {}, createAspectRatioStrategy: (_, __) => MockAspectRatioStrategy(), + createResolutionFilterWithOnePreferredSize: (_) => MockResolutionFilter(), ); final CameraInitializedEvent testCameraInitializedEvent = diff --git a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart index 141082ad9ac..5d6d2051212 100644 --- a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart +++ b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart @@ -3,51 +3,53 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i16; -import 'dart:typed_data' as _i32; +import 'dart:async' as _i17; +import 'dart:typed_data' as _i33; +import 'dart:ui' as _i11; -import 'package:camera_android_camerax/src/analyzer.dart' as _i15; -import 'package:camera_android_camerax/src/aspect_ratio_strategy.dart' as _i18; +import 'package:camera_android_camerax/src/analyzer.dart' as _i16; +import 'package:camera_android_camerax/src/aspect_ratio_strategy.dart' as _i19; import 'package:camera_android_camerax/src/camera.dart' as _i9; -import 'package:camera_android_camerax/src/camera2_camera_control.dart' as _i23; +import 'package:camera_android_camerax/src/camera2_camera_control.dart' as _i24; import 'package:camera_android_camerax/src/camera_control.dart' as _i3; import 'package:camera_android_camerax/src/camera_info.dart' as _i2; -import 'package:camera_android_camerax/src/camera_selector.dart' as _i25; -import 'package:camera_android_camerax/src/camera_state.dart' as _i19; +import 'package:camera_android_camerax/src/camera_selector.dart' as _i26; +import 'package:camera_android_camerax/src/camera_state.dart' as _i20; import 'package:camera_android_camerax/src/camerax_library.g.dart' as _i7; import 'package:camera_android_camerax/src/capture_request_options.dart' - as _i24; + as _i25; import 'package:camera_android_camerax/src/exposure_state.dart' as _i5; -import 'package:camera_android_camerax/src/fallback_strategy.dart' as _i26; -import 'package:camera_android_camerax/src/focus_metering_action.dart' as _i22; -import 'package:camera_android_camerax/src/focus_metering_result.dart' as _i21; -import 'package:camera_android_camerax/src/image_analysis.dart' as _i27; -import 'package:camera_android_camerax/src/image_capture.dart' as _i28; -import 'package:camera_android_camerax/src/image_proxy.dart' as _i17; +import 'package:camera_android_camerax/src/fallback_strategy.dart' as _i27; +import 'package:camera_android_camerax/src/focus_metering_action.dart' as _i23; +import 'package:camera_android_camerax/src/focus_metering_result.dart' as _i22; +import 'package:camera_android_camerax/src/image_analysis.dart' as _i28; +import 'package:camera_android_camerax/src/image_capture.dart' as _i29; +import 'package:camera_android_camerax/src/image_proxy.dart' as _i18; import 'package:camera_android_camerax/src/live_data.dart' as _i4; -import 'package:camera_android_camerax/src/observer.dart' as _i31; +import 'package:camera_android_camerax/src/observer.dart' as _i32; import 'package:camera_android_camerax/src/pending_recording.dart' as _i10; -import 'package:camera_android_camerax/src/plane_proxy.dart' as _i30; -import 'package:camera_android_camerax/src/preview.dart' as _i33; +import 'package:camera_android_camerax/src/plane_proxy.dart' as _i31; +import 'package:camera_android_camerax/src/preview.dart' as _i34; import 'package:camera_android_camerax/src/process_camera_provider.dart' - as _i34; -import 'package:camera_android_camerax/src/quality_selector.dart' as _i36; -import 'package:camera_android_camerax/src/recorder.dart' as _i11; + as _i35; +import 'package:camera_android_camerax/src/quality_selector.dart' as _i37; +import 'package:camera_android_camerax/src/recorder.dart' as _i12; import 'package:camera_android_camerax/src/recording.dart' as _i8; -import 'package:camera_android_camerax/src/resolution_selector.dart' as _i37; -import 'package:camera_android_camerax/src/resolution_strategy.dart' as _i38; -import 'package:camera_android_camerax/src/use_case.dart' as _i35; -import 'package:camera_android_camerax/src/video_capture.dart' as _i39; -import 'package:camera_android_camerax/src/zoom_state.dart' as _i20; +import 'package:camera_android_camerax/src/resolution_filter.dart' as _i38; +import 'package:camera_android_camerax/src/resolution_selector.dart' as _i39; +import 'package:camera_android_camerax/src/resolution_strategy.dart' as _i40; +import 'package:camera_android_camerax/src/use_case.dart' as _i36; +import 'package:camera_android_camerax/src/video_capture.dart' as _i41; +import 'package:camera_android_camerax/src/zoom_state.dart' as _i21; import 'package:camera_platform_interface/camera_platform_interface.dart' as _i6; -import 'package:flutter/foundation.dart' as _i14; -import 'package:flutter/services.dart' as _i13; -import 'package:flutter/widgets.dart' as _i12; +import 'package:flutter/foundation.dart' as _i15; +import 'package:flutter/services.dart' as _i14; +import 'package:flutter/widgets.dart' as _i13; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i29; +import 'package:mockito/src/dummies.dart' as _i30; -import 'test_camerax_library.g.dart' as _i40; +import 'test_camerax_library.g.dart' as _i42; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -167,8 +169,8 @@ class _FakePendingRecording_9 extends _i1.SmartFake ); } -class _FakeRecorder_10 extends _i1.SmartFake implements _i11.Recorder { - _FakeRecorder_10( +class _FakeSize_10 extends _i1.SmartFake implements _i11.Size { + _FakeSize_10( Object parent, Invocation parentInvocation, ) : super( @@ -177,8 +179,18 @@ class _FakeRecorder_10 extends _i1.SmartFake implements _i11.Recorder { ); } -class _FakeWidget_11 extends _i1.SmartFake implements _i12.Widget { - _FakeWidget_11( +class _FakeRecorder_11 extends _i1.SmartFake implements _i12.Recorder { + _FakeRecorder_11( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeWidget_12 extends _i1.SmartFake implements _i13.Widget { + _FakeWidget_12( Object parent, Invocation parentInvocation, ) : super( @@ -188,13 +200,13 @@ class _FakeWidget_11 extends _i1.SmartFake implements _i12.Widget { @override String toString( - {_i13.DiagnosticLevel? minLevel = _i13.DiagnosticLevel.info}) => + {_i14.DiagnosticLevel? minLevel = _i14.DiagnosticLevel.info}) => super.toString(); } -class _FakeInheritedWidget_12 extends _i1.SmartFake - implements _i12.InheritedWidget { - _FakeInheritedWidget_12( +class _FakeInheritedWidget_13 extends _i1.SmartFake + implements _i13.InheritedWidget { + _FakeInheritedWidget_13( Object parent, Invocation parentInvocation, ) : super( @@ -204,13 +216,13 @@ class _FakeInheritedWidget_12 extends _i1.SmartFake @override String toString( - {_i13.DiagnosticLevel? minLevel = _i13.DiagnosticLevel.info}) => + {_i14.DiagnosticLevel? minLevel = _i14.DiagnosticLevel.info}) => super.toString(); } -class _FakeDiagnosticsNode_13 extends _i1.SmartFake - implements _i14.DiagnosticsNode { - _FakeDiagnosticsNode_13( +class _FakeDiagnosticsNode_14 extends _i1.SmartFake + implements _i15.DiagnosticsNode { + _FakeDiagnosticsNode_14( Object parent, Invocation parentInvocation, ) : super( @@ -220,8 +232,8 @@ class _FakeDiagnosticsNode_13 extends _i1.SmartFake @override String toString({ - _i14.TextTreeConfiguration? parentConfiguration, - _i13.DiagnosticLevel? minLevel = _i13.DiagnosticLevel.info, + _i15.TextTreeConfiguration? parentConfiguration, + _i14.DiagnosticLevel? minLevel = _i14.DiagnosticLevel.info, }) => super.toString(); } @@ -230,15 +242,15 @@ class _FakeDiagnosticsNode_13 extends _i1.SmartFake /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockAnalyzer extends _i1.Mock implements _i15.Analyzer { +class MockAnalyzer extends _i1.Mock implements _i16.Analyzer { @override - _i16.Future Function(_i17.ImageProxy) get analyze => + _i17.Future Function(_i18.ImageProxy) get analyze => (super.noSuchMethod( Invocation.getter(#analyze), - returnValue: (_i17.ImageProxy imageProxy) => _i16.Future.value(), - returnValueForMissingStub: (_i17.ImageProxy imageProxy) => - _i16.Future.value(), - ) as _i16.Future Function(_i17.ImageProxy)); + returnValue: (_i18.ImageProxy imageProxy) => _i17.Future.value(), + returnValueForMissingStub: (_i18.ImageProxy imageProxy) => + _i17.Future.value(), + ) as _i17.Future Function(_i18.ImageProxy)); } /// A class which mocks [AspectRatioStrategy]. @@ -246,7 +258,7 @@ class MockAnalyzer extends _i1.Mock implements _i15.Analyzer { /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockAspectRatioStrategy extends _i1.Mock - implements _i18.AspectRatioStrategy { + implements _i19.AspectRatioStrategy { @override int get preferredAspectRatio => (super.noSuchMethod( Invocation.getter(#preferredAspectRatio), @@ -268,12 +280,12 @@ class MockAspectRatioStrategy extends _i1.Mock // ignore: must_be_immutable class MockCamera extends _i1.Mock implements _i9.Camera { @override - _i16.Future<_i2.CameraInfo> getCameraInfo() => (super.noSuchMethod( + _i17.Future<_i2.CameraInfo> getCameraInfo() => (super.noSuchMethod( Invocation.method( #getCameraInfo, [], ), - returnValue: _i16.Future<_i2.CameraInfo>.value(_FakeCameraInfo_0( + returnValue: _i17.Future<_i2.CameraInfo>.value(_FakeCameraInfo_0( this, Invocation.method( #getCameraInfo, @@ -281,22 +293,22 @@ class MockCamera extends _i1.Mock implements _i9.Camera { ), )), returnValueForMissingStub: - _i16.Future<_i2.CameraInfo>.value(_FakeCameraInfo_0( + _i17.Future<_i2.CameraInfo>.value(_FakeCameraInfo_0( this, Invocation.method( #getCameraInfo, [], ), )), - ) as _i16.Future<_i2.CameraInfo>); + ) as _i17.Future<_i2.CameraInfo>); @override - _i16.Future<_i3.CameraControl> getCameraControl() => (super.noSuchMethod( + _i17.Future<_i3.CameraControl> getCameraControl() => (super.noSuchMethod( Invocation.method( #getCameraControl, [], ), - returnValue: _i16.Future<_i3.CameraControl>.value(_FakeCameraControl_1( + returnValue: _i17.Future<_i3.CameraControl>.value(_FakeCameraControl_1( this, Invocation.method( #getCameraControl, @@ -304,14 +316,14 @@ class MockCamera extends _i1.Mock implements _i9.Camera { ), )), returnValueForMissingStub: - _i16.Future<_i3.CameraControl>.value(_FakeCameraControl_1( + _i17.Future<_i3.CameraControl>.value(_FakeCameraControl_1( this, Invocation.method( #getCameraControl, [], ), )), - ) as _i16.Future<_i3.CameraControl>); + ) as _i17.Future<_i3.CameraControl>); } /// A class which mocks [CameraInfo]. @@ -320,24 +332,24 @@ class MockCamera extends _i1.Mock implements _i9.Camera { // ignore: must_be_immutable class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { @override - _i16.Future getSensorRotationDegrees() => (super.noSuchMethod( + _i17.Future getSensorRotationDegrees() => (super.noSuchMethod( Invocation.method( #getSensorRotationDegrees, [], ), - returnValue: _i16.Future.value(0), - returnValueForMissingStub: _i16.Future.value(0), - ) as _i16.Future); + returnValue: _i17.Future.value(0), + returnValueForMissingStub: _i17.Future.value(0), + ) as _i17.Future); @override - _i16.Future<_i4.LiveData<_i19.CameraState>> getCameraState() => + _i17.Future<_i4.LiveData<_i20.CameraState>> getCameraState() => (super.noSuchMethod( Invocation.method( #getCameraState, [], ), - returnValue: _i16.Future<_i4.LiveData<_i19.CameraState>>.value( - _FakeLiveData_2<_i19.CameraState>( + returnValue: _i17.Future<_i4.LiveData<_i20.CameraState>>.value( + _FakeLiveData_2<_i20.CameraState>( this, Invocation.method( #getCameraState, @@ -345,23 +357,23 @@ class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { ), )), returnValueForMissingStub: - _i16.Future<_i4.LiveData<_i19.CameraState>>.value( - _FakeLiveData_2<_i19.CameraState>( + _i17.Future<_i4.LiveData<_i20.CameraState>>.value( + _FakeLiveData_2<_i20.CameraState>( this, Invocation.method( #getCameraState, [], ), )), - ) as _i16.Future<_i4.LiveData<_i19.CameraState>>); + ) as _i17.Future<_i4.LiveData<_i20.CameraState>>); @override - _i16.Future<_i5.ExposureState> getExposureState() => (super.noSuchMethod( + _i17.Future<_i5.ExposureState> getExposureState() => (super.noSuchMethod( Invocation.method( #getExposureState, [], ), - returnValue: _i16.Future<_i5.ExposureState>.value(_FakeExposureState_3( + returnValue: _i17.Future<_i5.ExposureState>.value(_FakeExposureState_3( this, Invocation.method( #getExposureState, @@ -369,24 +381,24 @@ class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { ), )), returnValueForMissingStub: - _i16.Future<_i5.ExposureState>.value(_FakeExposureState_3( + _i17.Future<_i5.ExposureState>.value(_FakeExposureState_3( this, Invocation.method( #getExposureState, [], ), )), - ) as _i16.Future<_i5.ExposureState>); + ) as _i17.Future<_i5.ExposureState>); @override - _i16.Future<_i4.LiveData<_i20.ZoomState>> getZoomState() => + _i17.Future<_i4.LiveData<_i21.ZoomState>> getZoomState() => (super.noSuchMethod( Invocation.method( #getZoomState, [], ), - returnValue: _i16.Future<_i4.LiveData<_i20.ZoomState>>.value( - _FakeLiveData_2<_i20.ZoomState>( + returnValue: _i17.Future<_i4.LiveData<_i21.ZoomState>>.value( + _FakeLiveData_2<_i21.ZoomState>( this, Invocation.method( #getZoomState, @@ -394,15 +406,15 @@ class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { ), )), returnValueForMissingStub: - _i16.Future<_i4.LiveData<_i20.ZoomState>>.value( - _FakeLiveData_2<_i20.ZoomState>( + _i17.Future<_i4.LiveData<_i21.ZoomState>>.value( + _FakeLiveData_2<_i21.ZoomState>( this, Invocation.method( #getZoomState, [], ), )), - ) as _i16.Future<_i4.LiveData<_i20.ZoomState>>); + ) as _i17.Future<_i4.LiveData<_i21.ZoomState>>); } /// A class which mocks [CameraControl]. @@ -411,58 +423,58 @@ class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { // ignore: must_be_immutable class MockCameraControl extends _i1.Mock implements _i3.CameraControl { @override - _i16.Future enableTorch(bool? torch) => (super.noSuchMethod( + _i17.Future enableTorch(bool? torch) => (super.noSuchMethod( Invocation.method( #enableTorch, [torch], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future setZoomRatio(double? ratio) => (super.noSuchMethod( + _i17.Future setZoomRatio(double? ratio) => (super.noSuchMethod( Invocation.method( #setZoomRatio, [ratio], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future<_i21.FocusMeteringResult?> startFocusAndMetering( - _i22.FocusMeteringAction? action) => + _i17.Future<_i22.FocusMeteringResult?> startFocusAndMetering( + _i23.FocusMeteringAction? action) => (super.noSuchMethod( Invocation.method( #startFocusAndMetering, [action], ), - returnValue: _i16.Future<_i21.FocusMeteringResult?>.value(), + returnValue: _i17.Future<_i22.FocusMeteringResult?>.value(), returnValueForMissingStub: - _i16.Future<_i21.FocusMeteringResult?>.value(), - ) as _i16.Future<_i21.FocusMeteringResult?>); + _i17.Future<_i22.FocusMeteringResult?>.value(), + ) as _i17.Future<_i22.FocusMeteringResult?>); @override - _i16.Future cancelFocusAndMetering() => (super.noSuchMethod( + _i17.Future cancelFocusAndMetering() => (super.noSuchMethod( Invocation.method( #cancelFocusAndMetering, [], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future setExposureCompensationIndex(int? index) => + _i17.Future setExposureCompensationIndex(int? index) => (super.noSuchMethod( Invocation.method( #setExposureCompensationIndex, [index], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); } /// A class which mocks [Camera2CameraControl]. @@ -470,7 +482,7 @@ class MockCameraControl extends _i1.Mock implements _i3.CameraControl { /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockCamera2CameraControl extends _i1.Mock - implements _i23.Camera2CameraControl { + implements _i24.Camera2CameraControl { @override _i3.CameraControl get cameraControl => (super.noSuchMethod( Invocation.getter(#cameraControl), @@ -485,16 +497,16 @@ class MockCamera2CameraControl extends _i1.Mock ) as _i3.CameraControl); @override - _i16.Future addCaptureRequestOptions( - _i24.CaptureRequestOptions? captureRequestOptions) => + _i17.Future addCaptureRequestOptions( + _i25.CaptureRequestOptions? captureRequestOptions) => (super.noSuchMethod( Invocation.method( #addCaptureRequestOptions, [captureRequestOptions], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); } /// A class which mocks [CameraImageData]. @@ -541,19 +553,19 @@ class MockCameraImageData extends _i1.Mock implements _i6.CameraImageData { /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockCameraSelector extends _i1.Mock implements _i25.CameraSelector { +class MockCameraSelector extends _i1.Mock implements _i26.CameraSelector { @override - _i16.Future> filter(List<_i2.CameraInfo>? cameraInfos) => + _i17.Future> filter(List<_i2.CameraInfo>? cameraInfos) => (super.noSuchMethod( Invocation.method( #filter, [cameraInfos], ), returnValue: - _i16.Future>.value(<_i2.CameraInfo>[]), + _i17.Future>.value(<_i2.CameraInfo>[]), returnValueForMissingStub: - _i16.Future>.value(<_i2.CameraInfo>[]), - ) as _i16.Future>); + _i17.Future>.value(<_i2.CameraInfo>[]), + ) as _i17.Future>); } /// A class which mocks [ExposureState]. @@ -587,7 +599,7 @@ class MockExposureState extends _i1.Mock implements _i5.ExposureState { /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockFallbackStrategy extends _i1.Mock implements _i26.FallbackStrategy { +class MockFallbackStrategy extends _i1.Mock implements _i27.FallbackStrategy { @override _i7.VideoQuality get quality => (super.noSuchMethod( Invocation.getter(#quality), @@ -609,86 +621,86 @@ class MockFallbackStrategy extends _i1.Mock implements _i26.FallbackStrategy { /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockFocusMeteringResult extends _i1.Mock - implements _i21.FocusMeteringResult { + implements _i22.FocusMeteringResult { @override - _i16.Future isFocusSuccessful() => (super.noSuchMethod( + _i17.Future isFocusSuccessful() => (super.noSuchMethod( Invocation.method( #isFocusSuccessful, [], ), - returnValue: _i16.Future.value(false), - returnValueForMissingStub: _i16.Future.value(false), - ) as _i16.Future); + returnValue: _i17.Future.value(false), + returnValueForMissingStub: _i17.Future.value(false), + ) as _i17.Future); } /// A class which mocks [ImageAnalysis]. /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockImageAnalysis extends _i1.Mock implements _i27.ImageAnalysis { +class MockImageAnalysis extends _i1.Mock implements _i28.ImageAnalysis { @override - _i16.Future setTargetRotation(int? rotation) => (super.noSuchMethod( + _i17.Future setTargetRotation(int? rotation) => (super.noSuchMethod( Invocation.method( #setTargetRotation, [rotation], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future setAnalyzer(_i15.Analyzer? analyzer) => (super.noSuchMethod( + _i17.Future setAnalyzer(_i16.Analyzer? analyzer) => (super.noSuchMethod( Invocation.method( #setAnalyzer, [analyzer], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future clearAnalyzer() => (super.noSuchMethod( + _i17.Future clearAnalyzer() => (super.noSuchMethod( Invocation.method( #clearAnalyzer, [], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); } /// A class which mocks [ImageCapture]. /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockImageCapture extends _i1.Mock implements _i28.ImageCapture { +class MockImageCapture extends _i1.Mock implements _i29.ImageCapture { @override - _i16.Future setTargetRotation(int? rotation) => (super.noSuchMethod( + _i17.Future setTargetRotation(int? rotation) => (super.noSuchMethod( Invocation.method( #setTargetRotation, [rotation], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future setFlashMode(int? newFlashMode) => (super.noSuchMethod( + _i17.Future setFlashMode(int? newFlashMode) => (super.noSuchMethod( Invocation.method( #setFlashMode, [newFlashMode], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future takePicture() => (super.noSuchMethod( + _i17.Future takePicture() => (super.noSuchMethod( Invocation.method( #takePicture, [], ), - returnValue: _i16.Future.value(_i29.dummyValue( + returnValue: _i17.Future.value(_i30.dummyValue( this, Invocation.method( #takePicture, @@ -696,21 +708,21 @@ class MockImageCapture extends _i1.Mock implements _i28.ImageCapture { ), )), returnValueForMissingStub: - _i16.Future.value(_i29.dummyValue( + _i17.Future.value(_i30.dummyValue( this, Invocation.method( #takePicture, [], ), )), - ) as _i16.Future); + ) as _i17.Future); } /// A class which mocks [ImageProxy]. /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockImageProxy extends _i1.Mock implements _i17.ImageProxy { +class MockImageProxy extends _i1.Mock implements _i18.ImageProxy { @override int get format => (super.noSuchMethod( Invocation.getter(#format), @@ -733,33 +745,33 @@ class MockImageProxy extends _i1.Mock implements _i17.ImageProxy { ) as int); @override - _i16.Future> getPlanes() => (super.noSuchMethod( + _i17.Future> getPlanes() => (super.noSuchMethod( Invocation.method( #getPlanes, [], ), returnValue: - _i16.Future>.value(<_i30.PlaneProxy>[]), + _i17.Future>.value(<_i31.PlaneProxy>[]), returnValueForMissingStub: - _i16.Future>.value(<_i30.PlaneProxy>[]), - ) as _i16.Future>); + _i17.Future>.value(<_i31.PlaneProxy>[]), + ) as _i17.Future>); @override - _i16.Future close() => (super.noSuchMethod( + _i17.Future close() => (super.noSuchMethod( Invocation.method( #close, [], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); } /// A class which mocks [Observer]. /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockObserver extends _i1.Mock implements _i31.Observer<_i19.CameraState> { +class MockObserver extends _i1.Mock implements _i32.Observer<_i20.CameraState> { @override void Function(Object) get onChanged => (super.noSuchMethod( Invocation.getter(#onChanged), @@ -783,12 +795,12 @@ class MockObserver extends _i1.Mock implements _i31.Observer<_i19.CameraState> { // ignore: must_be_immutable class MockPendingRecording extends _i1.Mock implements _i10.PendingRecording { @override - _i16.Future<_i8.Recording> start() => (super.noSuchMethod( + _i17.Future<_i8.Recording> start() => (super.noSuchMethod( Invocation.method( #start, [], ), - returnValue: _i16.Future<_i8.Recording>.value(_FakeRecording_6( + returnValue: _i17.Future<_i8.Recording>.value(_FakeRecording_6( this, Invocation.method( #start, @@ -796,27 +808,27 @@ class MockPendingRecording extends _i1.Mock implements _i10.PendingRecording { ), )), returnValueForMissingStub: - _i16.Future<_i8.Recording>.value(_FakeRecording_6( + _i17.Future<_i8.Recording>.value(_FakeRecording_6( this, Invocation.method( #start, [], ), )), - ) as _i16.Future<_i8.Recording>); + ) as _i17.Future<_i8.Recording>); } /// A class which mocks [PlaneProxy]. /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockPlaneProxy extends _i1.Mock implements _i30.PlaneProxy { +class MockPlaneProxy extends _i1.Mock implements _i31.PlaneProxy { @override - _i32.Uint8List get buffer => (super.noSuchMethod( + _i33.Uint8List get buffer => (super.noSuchMethod( Invocation.getter(#buffer), - returnValue: _i32.Uint8List(0), - returnValueForMissingStub: _i32.Uint8List(0), - ) as _i32.Uint8List); + returnValue: _i33.Uint8List(0), + returnValueForMissingStub: _i33.Uint8List(0), + ) as _i33.Uint8List); @override int get pixelStride => (super.noSuchMethod( @@ -837,26 +849,26 @@ class MockPlaneProxy extends _i1.Mock implements _i30.PlaneProxy { /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockPreview extends _i1.Mock implements _i33.Preview { +class MockPreview extends _i1.Mock implements _i34.Preview { @override - _i16.Future setTargetRotation(int? rotation) => (super.noSuchMethod( + _i17.Future setTargetRotation(int? rotation) => (super.noSuchMethod( Invocation.method( #setTargetRotation, [rotation], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future setSurfaceProvider() => (super.noSuchMethod( + _i17.Future setSurfaceProvider() => (super.noSuchMethod( Invocation.method( #setSurfaceProvider, [], ), - returnValue: _i16.Future.value(0), - returnValueForMissingStub: _i16.Future.value(0), - ) as _i16.Future); + returnValue: _i17.Future.value(0), + returnValueForMissingStub: _i17.Future.value(0), + ) as _i17.Future); @override void releaseFlutterSurfaceTexture() => super.noSuchMethod( @@ -868,13 +880,13 @@ class MockPreview extends _i1.Mock implements _i33.Preview { ); @override - _i16.Future<_i7.ResolutionInfo> getResolutionInfo() => (super.noSuchMethod( + _i17.Future<_i7.ResolutionInfo> getResolutionInfo() => (super.noSuchMethod( Invocation.method( #getResolutionInfo, [], ), returnValue: - _i16.Future<_i7.ResolutionInfo>.value(_FakeResolutionInfo_7( + _i17.Future<_i7.ResolutionInfo>.value(_FakeResolutionInfo_7( this, Invocation.method( #getResolutionInfo, @@ -882,14 +894,14 @@ class MockPreview extends _i1.Mock implements _i33.Preview { ), )), returnValueForMissingStub: - _i16.Future<_i7.ResolutionInfo>.value(_FakeResolutionInfo_7( + _i17.Future<_i7.ResolutionInfo>.value(_FakeResolutionInfo_7( this, Invocation.method( #getResolutionInfo, [], ), )), - ) as _i16.Future<_i7.ResolutionInfo>); + ) as _i17.Future<_i7.ResolutionInfo>); } /// A class which mocks [ProcessCameraProvider]. @@ -897,24 +909,24 @@ class MockPreview extends _i1.Mock implements _i33.Preview { /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockProcessCameraProvider extends _i1.Mock - implements _i34.ProcessCameraProvider { + implements _i35.ProcessCameraProvider { @override - _i16.Future> getAvailableCameraInfos() => + _i17.Future> getAvailableCameraInfos() => (super.noSuchMethod( Invocation.method( #getAvailableCameraInfos, [], ), returnValue: - _i16.Future>.value(<_i2.CameraInfo>[]), + _i17.Future>.value(<_i2.CameraInfo>[]), returnValueForMissingStub: - _i16.Future>.value(<_i2.CameraInfo>[]), - ) as _i16.Future>); + _i17.Future>.value(<_i2.CameraInfo>[]), + ) as _i17.Future>); @override - _i16.Future<_i9.Camera> bindToLifecycle( - _i25.CameraSelector? cameraSelector, - List<_i35.UseCase>? useCases, + _i17.Future<_i9.Camera> bindToLifecycle( + _i26.CameraSelector? cameraSelector, + List<_i36.UseCase>? useCases, ) => (super.noSuchMethod( Invocation.method( @@ -924,7 +936,7 @@ class MockProcessCameraProvider extends _i1.Mock useCases, ], ), - returnValue: _i16.Future<_i9.Camera>.value(_FakeCamera_8( + returnValue: _i17.Future<_i9.Camera>.value(_FakeCamera_8( this, Invocation.method( #bindToLifecycle, @@ -934,7 +946,7 @@ class MockProcessCameraProvider extends _i1.Mock ], ), )), - returnValueForMissingStub: _i16.Future<_i9.Camera>.value(_FakeCamera_8( + returnValueForMissingStub: _i17.Future<_i9.Camera>.value(_FakeCamera_8( this, Invocation.method( #bindToLifecycle, @@ -944,20 +956,20 @@ class MockProcessCameraProvider extends _i1.Mock ], ), )), - ) as _i16.Future<_i9.Camera>); + ) as _i17.Future<_i9.Camera>); @override - _i16.Future isBound(_i35.UseCase? useCase) => (super.noSuchMethod( + _i17.Future isBound(_i36.UseCase? useCase) => (super.noSuchMethod( Invocation.method( #isBound, [useCase], ), - returnValue: _i16.Future.value(false), - returnValueForMissingStub: _i16.Future.value(false), - ) as _i16.Future); + returnValue: _i17.Future.value(false), + returnValueForMissingStub: _i17.Future.value(false), + ) as _i17.Future); @override - void unbind(List<_i35.UseCase>? useCases) => super.noSuchMethod( + void unbind(List<_i36.UseCase>? useCases) => super.noSuchMethod( Invocation.method( #unbind, [useCases], @@ -979,7 +991,7 @@ class MockProcessCameraProvider extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockQualitySelector extends _i1.Mock implements _i36.QualitySelector { +class MockQualitySelector extends _i1.Mock implements _i37.QualitySelector { @override List<_i7.VideoQualityData> get qualityList => (super.noSuchMethod( Invocation.getter(#qualityList), @@ -992,16 +1004,16 @@ class MockQualitySelector extends _i1.Mock implements _i36.QualitySelector { /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockRecorder extends _i1.Mock implements _i11.Recorder { +class MockRecorder extends _i1.Mock implements _i12.Recorder { @override - _i16.Future<_i10.PendingRecording> prepareRecording(String? path) => + _i17.Future<_i10.PendingRecording> prepareRecording(String? path) => (super.noSuchMethod( Invocation.method( #prepareRecording, [path], ), returnValue: - _i16.Future<_i10.PendingRecording>.value(_FakePendingRecording_9( + _i17.Future<_i10.PendingRecording>.value(_FakePendingRecording_9( this, Invocation.method( #prepareRecording, @@ -1009,14 +1021,33 @@ class MockRecorder extends _i1.Mock implements _i11.Recorder { ), )), returnValueForMissingStub: - _i16.Future<_i10.PendingRecording>.value(_FakePendingRecording_9( + _i17.Future<_i10.PendingRecording>.value(_FakePendingRecording_9( this, Invocation.method( #prepareRecording, [path], ), )), - ) as _i16.Future<_i10.PendingRecording>); + ) as _i17.Future<_i10.PendingRecording>); +} + +/// A class which mocks [ResolutionFilter]. +/// +/// See the documentation for Mockito's code generation for more information. +// ignore: must_be_immutable +class MockResolutionFilter extends _i1.Mock implements _i38.ResolutionFilter { + @override + _i11.Size get preferredResolution => (super.noSuchMethod( + Invocation.getter(#preferredResolution), + returnValue: _FakeSize_10( + this, + Invocation.getter(#preferredResolution), + ), + returnValueForMissingStub: _FakeSize_10( + this, + Invocation.getter(#preferredResolution), + ), + ) as _i11.Size); } /// A class which mocks [ResolutionSelector]. @@ -1024,14 +1055,14 @@ class MockRecorder extends _i1.Mock implements _i11.Recorder { /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockResolutionSelector extends _i1.Mock - implements _i37.ResolutionSelector {} + implements _i39.ResolutionSelector {} /// A class which mocks [ResolutionStrategy]. /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockResolutionStrategy extends _i1.Mock - implements _i38.ResolutionStrategy {} + implements _i40.ResolutionStrategy {} /// A class which mocks [Recording]. /// @@ -1039,68 +1070,68 @@ class MockResolutionStrategy extends _i1.Mock // ignore: must_be_immutable class MockRecording extends _i1.Mock implements _i8.Recording { @override - _i16.Future close() => (super.noSuchMethod( + _i17.Future close() => (super.noSuchMethod( Invocation.method( #close, [], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future pause() => (super.noSuchMethod( + _i17.Future pause() => (super.noSuchMethod( Invocation.method( #pause, [], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future resume() => (super.noSuchMethod( + _i17.Future resume() => (super.noSuchMethod( Invocation.method( #resume, [], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future stop() => (super.noSuchMethod( + _i17.Future stop() => (super.noSuchMethod( Invocation.method( #stop, [], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); } /// A class which mocks [VideoCapture]. /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockVideoCapture extends _i1.Mock implements _i39.VideoCapture { +class MockVideoCapture extends _i1.Mock implements _i41.VideoCapture { @override - _i16.Future setTargetRotation(int? rotation) => (super.noSuchMethod( + _i17.Future setTargetRotation(int? rotation) => (super.noSuchMethod( Invocation.method( #setTargetRotation, [rotation], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future<_i11.Recorder> getOutput() => (super.noSuchMethod( + _i17.Future<_i12.Recorder> getOutput() => (super.noSuchMethod( Invocation.method( #getOutput, [], ), - returnValue: _i16.Future<_i11.Recorder>.value(_FakeRecorder_10( + returnValue: _i17.Future<_i12.Recorder>.value(_FakeRecorder_11( this, Invocation.method( #getOutput, @@ -1108,32 +1139,32 @@ class MockVideoCapture extends _i1.Mock implements _i39.VideoCapture { ), )), returnValueForMissingStub: - _i16.Future<_i11.Recorder>.value(_FakeRecorder_10( + _i17.Future<_i12.Recorder>.value(_FakeRecorder_11( this, Invocation.method( #getOutput, [], ), )), - ) as _i16.Future<_i11.Recorder>); + ) as _i17.Future<_i12.Recorder>); } /// A class which mocks [BuildContext]. /// /// See the documentation for Mockito's code generation for more information. -class MockBuildContext extends _i1.Mock implements _i12.BuildContext { +class MockBuildContext extends _i1.Mock implements _i13.BuildContext { @override - _i12.Widget get widget => (super.noSuchMethod( + _i13.Widget get widget => (super.noSuchMethod( Invocation.getter(#widget), - returnValue: _FakeWidget_11( + returnValue: _FakeWidget_12( this, Invocation.getter(#widget), ), - returnValueForMissingStub: _FakeWidget_11( + returnValueForMissingStub: _FakeWidget_12( this, Invocation.getter(#widget), ), - ) as _i12.Widget); + ) as _i13.Widget); @override bool get mounted => (super.noSuchMethod( @@ -1150,8 +1181,8 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { ) as bool); @override - _i12.InheritedWidget dependOnInheritedElement( - _i12.InheritedElement? ancestor, { + _i13.InheritedWidget dependOnInheritedElement( + _i13.InheritedElement? ancestor, { Object? aspect, }) => (super.noSuchMethod( @@ -1160,7 +1191,7 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { [ancestor], {#aspect: aspect}, ), - returnValue: _FakeInheritedWidget_12( + returnValue: _FakeInheritedWidget_13( this, Invocation.method( #dependOnInheritedElement, @@ -1168,7 +1199,7 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { {#aspect: aspect}, ), ), - returnValueForMissingStub: _FakeInheritedWidget_12( + returnValueForMissingStub: _FakeInheritedWidget_13( this, Invocation.method( #dependOnInheritedElement, @@ -1176,10 +1207,10 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { {#aspect: aspect}, ), ), - ) as _i12.InheritedWidget); + ) as _i13.InheritedWidget); @override - void visitAncestorElements(_i12.ConditionalElementVisitor? visitor) => + void visitAncestorElements(_i13.ConditionalElementVisitor? visitor) => super.noSuchMethod( Invocation.method( #visitAncestorElements, @@ -1189,7 +1220,7 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { ); @override - void visitChildElements(_i12.ElementVisitor? visitor) => super.noSuchMethod( + void visitChildElements(_i13.ElementVisitor? visitor) => super.noSuchMethod( Invocation.method( #visitChildElements, [visitor], @@ -1198,7 +1229,7 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { ); @override - void dispatchNotification(_i12.Notification? notification) => + void dispatchNotification(_i13.Notification? notification) => super.noSuchMethod( Invocation.method( #dispatchNotification, @@ -1208,9 +1239,9 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { ); @override - _i14.DiagnosticsNode describeElement( + _i15.DiagnosticsNode describeElement( String? name, { - _i14.DiagnosticsTreeStyle? style = _i14.DiagnosticsTreeStyle.errorProperty, + _i15.DiagnosticsTreeStyle? style = _i15.DiagnosticsTreeStyle.errorProperty, }) => (super.noSuchMethod( Invocation.method( @@ -1218,7 +1249,7 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { [name], {#style: style}, ), - returnValue: _FakeDiagnosticsNode_13( + returnValue: _FakeDiagnosticsNode_14( this, Invocation.method( #describeElement, @@ -1226,7 +1257,7 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { {#style: style}, ), ), - returnValueForMissingStub: _FakeDiagnosticsNode_13( + returnValueForMissingStub: _FakeDiagnosticsNode_14( this, Invocation.method( #describeElement, @@ -1234,12 +1265,12 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { {#style: style}, ), ), - ) as _i14.DiagnosticsNode); + ) as _i15.DiagnosticsNode); @override - _i14.DiagnosticsNode describeWidget( + _i15.DiagnosticsNode describeWidget( String? name, { - _i14.DiagnosticsTreeStyle? style = _i14.DiagnosticsTreeStyle.errorProperty, + _i15.DiagnosticsTreeStyle? style = _i15.DiagnosticsTreeStyle.errorProperty, }) => (super.noSuchMethod( Invocation.method( @@ -1247,7 +1278,7 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { [name], {#style: style}, ), - returnValue: _FakeDiagnosticsNode_13( + returnValue: _FakeDiagnosticsNode_14( this, Invocation.method( #describeWidget, @@ -1255,7 +1286,7 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { {#style: style}, ), ), - returnValueForMissingStub: _FakeDiagnosticsNode_13( + returnValueForMissingStub: _FakeDiagnosticsNode_14( this, Invocation.method( #describeWidget, @@ -1263,10 +1294,10 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { {#style: style}, ), ), - ) as _i14.DiagnosticsNode); + ) as _i15.DiagnosticsNode); @override - List<_i14.DiagnosticsNode> describeMissingAncestor( + List<_i15.DiagnosticsNode> describeMissingAncestor( {required Type? expectedAncestorType}) => (super.noSuchMethod( Invocation.method( @@ -1274,39 +1305,39 @@ class MockBuildContext extends _i1.Mock implements _i12.BuildContext { [], {#expectedAncestorType: expectedAncestorType}, ), - returnValue: <_i14.DiagnosticsNode>[], - returnValueForMissingStub: <_i14.DiagnosticsNode>[], - ) as List<_i14.DiagnosticsNode>); + returnValue: <_i15.DiagnosticsNode>[], + returnValueForMissingStub: <_i15.DiagnosticsNode>[], + ) as List<_i15.DiagnosticsNode>); @override - _i14.DiagnosticsNode describeOwnershipChain(String? name) => + _i15.DiagnosticsNode describeOwnershipChain(String? name) => (super.noSuchMethod( Invocation.method( #describeOwnershipChain, [name], ), - returnValue: _FakeDiagnosticsNode_13( + returnValue: _FakeDiagnosticsNode_14( this, Invocation.method( #describeOwnershipChain, [name], ), ), - returnValueForMissingStub: _FakeDiagnosticsNode_13( + returnValueForMissingStub: _FakeDiagnosticsNode_14( this, Invocation.method( #describeOwnershipChain, [name], ), ), - ) as _i14.DiagnosticsNode); + ) as _i15.DiagnosticsNode); } /// A class which mocks [TestInstanceManagerHostApi]. /// /// See the documentation for Mockito's code generation for more information. class MockTestInstanceManagerHostApi extends _i1.Mock - implements _i40.TestInstanceManagerHostApi { + implements _i42.TestInstanceManagerHostApi { @override void clear() => super.noSuchMethod( Invocation.method( @@ -1321,19 +1352,19 @@ class MockTestInstanceManagerHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestSystemServicesHostApi extends _i1.Mock - implements _i40.TestSystemServicesHostApi { + implements _i42.TestSystemServicesHostApi { @override - _i16.Future<_i7.CameraPermissionsErrorData?> requestCameraPermissions( + _i17.Future<_i7.CameraPermissionsErrorData?> requestCameraPermissions( bool? enableAudio) => (super.noSuchMethod( Invocation.method( #requestCameraPermissions, [enableAudio], ), - returnValue: _i16.Future<_i7.CameraPermissionsErrorData?>.value(), + returnValue: _i17.Future<_i7.CameraPermissionsErrorData?>.value(), returnValueForMissingStub: - _i16.Future<_i7.CameraPermissionsErrorData?>.value(), - ) as _i16.Future<_i7.CameraPermissionsErrorData?>); + _i17.Future<_i7.CameraPermissionsErrorData?>.value(), + ) as _i17.Future<_i7.CameraPermissionsErrorData?>); @override String getTempFilePath( @@ -1348,7 +1379,7 @@ class MockTestSystemServicesHostApi extends _i1.Mock suffix, ], ), - returnValue: _i29.dummyValue( + returnValue: _i30.dummyValue( this, Invocation.method( #getTempFilePath, @@ -1358,7 +1389,7 @@ class MockTestSystemServicesHostApi extends _i1.Mock ], ), ), - returnValueForMissingStub: _i29.dummyValue( + returnValueForMissingStub: _i30.dummyValue( this, Invocation.method( #getTempFilePath, @@ -1375,7 +1406,7 @@ class MockTestSystemServicesHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockZoomState extends _i1.Mock implements _i20.ZoomState { +class MockZoomState extends _i1.Mock implements _i21.ZoomState { @override double get minZoomRatio => (super.noSuchMethod( Invocation.getter(#minZoomRatio), @@ -1396,31 +1427,31 @@ class MockZoomState extends _i1.Mock implements _i20.ZoomState { /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockLiveCameraState extends _i1.Mock - implements _i4.LiveData<_i19.CameraState> { + implements _i4.LiveData<_i20.CameraState> { MockLiveCameraState() { _i1.throwOnMissingStub(this); } @override - _i16.Future observe(_i31.Observer<_i19.CameraState>? observer) => + _i17.Future observe(_i32.Observer<_i20.CameraState>? observer) => (super.noSuchMethod( Invocation.method( #observe, [observer], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future removeObservers() => (super.noSuchMethod( + _i17.Future removeObservers() => (super.noSuchMethod( Invocation.method( #removeObservers, [], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); } /// A class which mocks [LiveData]. @@ -1428,29 +1459,29 @@ class MockLiveCameraState extends _i1.Mock /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockLiveZoomState extends _i1.Mock - implements _i4.LiveData<_i20.ZoomState> { + implements _i4.LiveData<_i21.ZoomState> { MockLiveZoomState() { _i1.throwOnMissingStub(this); } @override - _i16.Future observe(_i31.Observer<_i20.ZoomState>? observer) => + _i17.Future observe(_i32.Observer<_i21.ZoomState>? observer) => (super.noSuchMethod( Invocation.method( #observe, [observer], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); @override - _i16.Future removeObservers() => (super.noSuchMethod( + _i17.Future removeObservers() => (super.noSuchMethod( Invocation.method( #removeObservers, [], ), - returnValue: _i16.Future.value(), - returnValueForMissingStub: _i16.Future.value(), - ) as _i16.Future); + returnValue: _i17.Future.value(), + returnValueForMissingStub: _i17.Future.value(), + ) as _i17.Future); } diff --git a/packages/camera/camera_android_camerax/test/resolution_filter_test.dart b/packages/camera/camera_android_camerax/test/resolution_filter_test.dart new file mode 100644 index 00000000000..3011cf0f455 --- /dev/null +++ b/packages/camera/camera_android_camerax/test/resolution_filter_test.dart @@ -0,0 +1,91 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; + +import 'package:camera_android_camerax/src/camerax_library.g.dart'; +import 'package:camera_android_camerax/src/instance_manager.dart'; +import 'package:camera_android_camerax/src/resolution_filter.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'resolution_filter_test.mocks.dart'; +import 'test_camerax_library.g.dart'; + +@GenerateMocks([ + TestResolutionFilterHostApi, + TestInstanceManagerHostApi, +]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('ResolutionFilter', () { + tearDown(() { + TestResolutionFilterHostApi.setup(null); + TestInstanceManagerHostApi.setup(null); + }); + + test( + 'detached ResolutionFilter.onePreferredSize constructor does not make call to Host API createWithOnePreferredSize', + () { + final MockTestResolutionFilterHostApi mockApi = + MockTestResolutionFilterHostApi(); + TestResolutionFilterHostApi.setup(mockApi); + TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi()); + + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + + const double preferredWidth = 270; + const double preferredHeight = 720; + const Size preferredResolution = Size(preferredWidth, preferredHeight); + + ResolutionFilter.onePreferredSizeDetached( + preferredResolution: preferredResolution, + instanceManager: instanceManager, + ); + + verifyNever(mockApi.createWithOnePreferredSize( + argThat(isA()), + argThat(isA() + .having( + (ResolutionInfo size) => size.width, 'width', preferredWidth) + .having((ResolutionInfo size) => size.height, 'height', + preferredHeight)), + )); + }); + + test( + 'HostApi createWithOnePreferredSize creates expected ResolutionStrategy', + () { + final MockTestResolutionFilterHostApi mockApi = + MockTestResolutionFilterHostApi(); + TestResolutionFilterHostApi.setup(mockApi); + TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi()); + + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + + const double preferredWidth = 890; + const double preferredHeight = 980; + const Size preferredResolution = Size(preferredWidth, preferredHeight); + + final ResolutionFilter instance = ResolutionFilter.onePreferredSize( + preferredResolution: preferredResolution, + instanceManager: instanceManager, + ); + verify(mockApi.createWithOnePreferredSize( + instanceManager.getIdentifier(instance), + argThat(isA() + .having( + (ResolutionInfo size) => size.width, 'width', preferredWidth) + .having((ResolutionInfo size) => size.height, 'height', + preferredHeight)), + )); + }); + }); +} diff --git a/packages/camera/camera_android_camerax/test/resolution_filter_test.mocks.dart b/packages/camera/camera_android_camerax/test/resolution_filter_test.mocks.dart new file mode 100644 index 00000000000..cf859c7b637 --- /dev/null +++ b/packages/camera/camera_android_camerax/test/resolution_filter_test.mocks.dart @@ -0,0 +1,67 @@ +// Mocks generated by Mockito 5.4.4 from annotations +// in camera_android_camerax/test/resolution_filter_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:camera_android_camerax/src/camerax_library.g.dart' as _i3; +import 'package:mockito/mockito.dart' as _i1; + +import 'test_camerax_library.g.dart' as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +/// A class which mocks [TestResolutionFilterHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestResolutionFilterHostApi extends _i1.Mock + implements _i2.TestResolutionFilterHostApi { + MockTestResolutionFilterHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void createWithOnePreferredSize( + int? identifier, + _i3.ResolutionInfo? preferredResolution, + ) => + super.noSuchMethod( + Invocation.method( + #createWithOnePreferredSize, + [ + identifier, + preferredResolution, + ], + ), + returnValueForMissingStub: null, + ); +} + +/// A class which mocks [TestInstanceManagerHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestInstanceManagerHostApi extends _i1.Mock + implements _i2.TestInstanceManagerHostApi { + MockTestInstanceManagerHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void clear() => super.noSuchMethod( + Invocation.method( + #clear, + [], + ), + returnValueForMissingStub: null, + ); +} diff --git a/packages/camera/camera_android_camerax/test/resolution_selector_test.dart b/packages/camera/camera_android_camerax/test/resolution_selector_test.dart index 45ecef576a3..7aaa37ae1ea 100644 --- a/packages/camera/camera_android_camerax/test/resolution_selector_test.dart +++ b/packages/camera/camera_android_camerax/test/resolution_selector_test.dart @@ -6,6 +6,7 @@ import 'dart:ui'; import 'package:camera_android_camerax/src/aspect_ratio_strategy.dart'; import 'package:camera_android_camerax/src/instance_manager.dart'; +import 'package:camera_android_camerax/src/resolution_filter.dart'; import 'package:camera_android_camerax/src/resolution_selector.dart'; import 'package:camera_android_camerax/src/resolution_strategy.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -17,6 +18,7 @@ import 'test_camerax_library.g.dart'; @GenerateMocks([ AspectRatioStrategy, + ResolutionFilter, ResolutionStrategy, TestResolutionSelectorHostApi, TestInstanceManagerHostApi, @@ -54,15 +56,13 @@ void main() { ResolutionSelector.detached( resolutionStrategy: MockResolutionStrategy(), + resolutionFilter: MockResolutionFilter(), aspectRatioStrategy: MockAspectRatioStrategy(), instanceManager: instanceManager, ); - verifyNever(mockApi.create( - argThat(isA()), - argThat(isA()), - argThat(isA()), - )); + verifyNever(mockApi.create(argThat(isA()), argThat(isA()), + argThat(isA()), argThat(isA()))); }); test('HostApi create creates expected ResolutionSelector instance', () { @@ -91,6 +91,20 @@ void main() { ), ); + final ResolutionFilter resolutionFilter = + ResolutionFilter.onePreferredSizeDetached( + preferredResolution: const Size(30, 40)); + const int resolutionFilterIdentifier = 54; + instanceManager.addHostCreatedInstance( + resolutionFilter, + resolutionFilterIdentifier, + onCopy: (ResolutionFilter original) => + ResolutionFilter.onePreferredSizeDetached( + preferredResolution: original.preferredResolution, + instanceManager: instanceManager, + ), + ); + final AspectRatioStrategy aspectRatioStrategy = AspectRatioStrategy.detached( preferredAspectRatio: AspectRatio.ratio4To3, @@ -110,6 +124,7 @@ void main() { final ResolutionSelector instance = ResolutionSelector( resolutionStrategy: resolutionStrategy, + resolutionFilter: resolutionFilter, aspectRatioStrategy: aspectRatioStrategy, instanceManager: instanceManager, ); @@ -117,6 +132,7 @@ void main() { verify(mockApi.create( instanceManager.getIdentifier(instance), resolutionStrategyIdentifier, + resolutionFilterIdentifier, aspectRatioStrategyIdentifier, )); }); diff --git a/packages/camera/camera_android_camerax/test/resolution_selector_test.mocks.dart b/packages/camera/camera_android_camerax/test/resolution_selector_test.mocks.dart index 541092f089a..c36ae699e8a 100644 --- a/packages/camera/camera_android_camerax/test/resolution_selector_test.mocks.dart +++ b/packages/camera/camera_android_camerax/test/resolution_selector_test.mocks.dart @@ -3,11 +3,14 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:camera_android_camerax/src/aspect_ratio_strategy.dart' as _i2; -import 'package:camera_android_camerax/src/resolution_strategy.dart' as _i3; +import 'dart:ui' as _i2; + +import 'package:camera_android_camerax/src/aspect_ratio_strategy.dart' as _i3; +import 'package:camera_android_camerax/src/resolution_filter.dart' as _i4; +import 'package:camera_android_camerax/src/resolution_strategy.dart' as _i5; import 'package:mockito/mockito.dart' as _i1; -import 'test_camerax_library.g.dart' as _i4; +import 'test_camerax_library.g.dart' as _i6; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -22,12 +25,22 @@ import 'test_camerax_library.g.dart' as _i4; // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +class _FakeSize_0 extends _i1.SmartFake implements _i2.Size { + _FakeSize_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + /// A class which mocks [AspectRatioStrategy]. /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockAspectRatioStrategy extends _i1.Mock - implements _i2.AspectRatioStrategy { + implements _i3.AspectRatioStrategy { MockAspectRatioStrategy() { _i1.throwOnMissingStub(this); } @@ -45,12 +58,31 @@ class MockAspectRatioStrategy extends _i1.Mock ) as int); } +/// A class which mocks [ResolutionFilter]. +/// +/// See the documentation for Mockito's code generation for more information. +// ignore: must_be_immutable +class MockResolutionFilter extends _i1.Mock implements _i4.ResolutionFilter { + MockResolutionFilter() { + _i1.throwOnMissingStub(this); + } + + @override + _i2.Size get preferredResolution => (super.noSuchMethod( + Invocation.getter(#preferredResolution), + returnValue: _FakeSize_0( + this, + Invocation.getter(#preferredResolution), + ), + ) as _i2.Size); +} + /// A class which mocks [ResolutionStrategy]. /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable class MockResolutionStrategy extends _i1.Mock - implements _i3.ResolutionStrategy { + implements _i5.ResolutionStrategy { MockResolutionStrategy() { _i1.throwOnMissingStub(this); } @@ -60,7 +92,7 @@ class MockResolutionStrategy extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestResolutionSelectorHostApi extends _i1.Mock - implements _i4.TestResolutionSelectorHostApi { + implements _i6.TestResolutionSelectorHostApi { MockTestResolutionSelectorHostApi() { _i1.throwOnMissingStub(this); } @@ -69,6 +101,7 @@ class MockTestResolutionSelectorHostApi extends _i1.Mock void create( int? identifier, int? resolutionStrategyIdentifier, + int? resolutionSelectorIdentifier, int? aspectRatioStrategyIdentifier, ) => super.noSuchMethod( @@ -77,6 +110,7 @@ class MockTestResolutionSelectorHostApi extends _i1.Mock [ identifier, resolutionStrategyIdentifier, + resolutionSelectorIdentifier, aspectRatioStrategyIdentifier, ], ), @@ -88,7 +122,7 @@ class MockTestResolutionSelectorHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestInstanceManagerHostApi extends _i1.Mock - implements _i4.TestInstanceManagerHostApi { + implements _i6.TestInstanceManagerHostApi { MockTestInstanceManagerHostApi() { _i1.throwOnMissingStub(this); } diff --git a/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart b/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart index 94aa71cff26..8080e4276fc 100644 --- a/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart +++ b/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart @@ -2364,8 +2364,8 @@ abstract class TestCamera2CameraControlHostApi { } } -class _ResolutionFilterHostApiCodec extends StandardMessageCodec { - const _ResolutionFilterHostApiCodec(); +class _TestResolutionFilterHostApiCodec extends StandardMessageCodec { + const _TestResolutionFilterHostApiCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { if (value is ResolutionInfo) { @@ -2387,15 +2387,16 @@ class _ResolutionFilterHostApiCodec extends StandardMessageCodec { } } -abstract class ResolutionFilterHostApi { +abstract class TestResolutionFilterHostApi { static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => TestDefaultBinaryMessengerBinding.instance; - static const MessageCodec codec = _ResolutionFilterHostApiCodec(); + static const MessageCodec codec = + _TestResolutionFilterHostApiCodec(); void createWithOnePreferredSize( int identifier, ResolutionInfo preferredResolution); - static void setup(ResolutionFilterHostApi? api, + static void setup(TestResolutionFilterHostApi? api, {BinaryMessenger? binaryMessenger}) { { final BasicMessageChannel channel = BasicMessageChannel( From f45e9d129546d5e73ea88a5c9b1deba8fdfbb00c Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 26 Mar 2024 11:22:15 -0700 Subject: [PATCH 08/10] Update changelog --- packages/camera/camera_android_camerax/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/camera/camera_android_camerax/CHANGELOG.md b/packages/camera/camera_android_camerax/CHANGELOG.md index 6d5ddf51851..68fdea1e755 100644 --- a/packages/camera/camera_android_camerax/CHANGELOG.md +++ b/packages/camera/camera_android_camerax/CHANGELOG.md @@ -1,6 +1,8 @@ ## 0.6.1 * Modifies resolution selection logic to use an `AspectRatioStrategy` for all aspect ratios supported by CameraX. +* Adds `ResolutionFilter` to resolution selection logic to prioritize resolutions that match + the defined `ResolutionPreset`s. ## 0.6.0+1 From 196fd89b07d60b1e86947857864126dfb6ae2b1c Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 26 Mar 2024 12:34:15 -0700 Subject: [PATCH 09/10] Nits --- .../camerax/ResolutionFilterHostApiImpl.java | 2 +- .../ResolutionSelectorHostApiImpl.java | 6 ++--- .../plugins/camerax/ResolutionFilterTest.java | 8 +++--- .../camerax/ResolutionSelectorTest.java | 8 +++--- .../lib/src/camerax_proxy.dart | 2 +- .../lib/src/resolution_filter.dart | 25 +++++++++++-------- .../test/resolution_filter_test.dart | 3 +-- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java index abaf1659272..8601ece52d7 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java @@ -27,7 +27,7 @@ public class ResolutionFilterHostApiImpl implements ResolutionFilterHostApi { public static class ResolutionFilterProxy { /** * Creates an instance of {@link ResolutionFilter} that moves the {@code preferredSize} to the - * front of the list of supported resolutions such that it can be prioritized by CameraX. + * front of the list of supported resolutions so that it can be prioritized by CameraX. */ @NonNull public ResolutionFilter createWithOnePreferredSize(@NonNull Size preferredSize) { diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionSelectorHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionSelectorHostApiImpl.java index 96cb1f3ad9b..0a5fe750d16 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionSelectorHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionSelectorHostApiImpl.java @@ -37,12 +37,12 @@ public ResolutionSelector create( if (resolutionStrategy != null) { builder.setResolutionStrategy(resolutionStrategy); } - if (resolutionFilter != null) { - builder.setResolutionFilter(resolutionFilter); - } if (aspectRatioStrategy != null) { builder.setAspectRatioStrategy(aspectRatioStrategy); } + if (resolutionFilter != null) { + builder.setResolutionFilter(resolutionFilter); + } return builder.build(); } } diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java index 8fe3d3538f9..7e086d938d4 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java @@ -24,7 +24,6 @@ @RunWith(RobolectricTestRunner.class) public class ResolutionFilterTest { @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); - @Mock public ResolutionFilter mockResolutionFilter; InstanceManager instanceManager; @@ -40,7 +39,6 @@ public void tearDown() { @Test public void hostApiCreateWithOnePreferredSize_createsExpectedResolutionFilterInstance() { - final android.util.Size lala = new android.util.Size(720, 480); final ResolutionFilterHostApiImpl hostApi = new ResolutionFilterHostApiImpl(instanceManager); final long instanceIdentifier = 50; final long preferredResolutionWidth = 20; @@ -53,7 +51,7 @@ public void hostApiCreateWithOnePreferredSize_createsExpectedResolutionFilterIns hostApi.createWithOnePreferredSize(instanceIdentifier, preferredResolution); - // Test instance filters supported resolutions as expected. + // Test that instance filters supported resolutions as expected. final ResolutionFilter resolutionFilter = instanceManager.getInstance(instanceIdentifier); final Size fakeSupportedSize1 = new Size(720, 480); final Size fakeSupportedSize2 = new Size(20, 80); @@ -67,11 +65,11 @@ public void hostApiCreateWithOnePreferredSize_createsExpectedResolutionFilterIns fakeSupportedSizes.add(preferredSize); fakeSupportedSizes.add(fakeSupportedSize3); - // Test case where preferred resolution is supported. + // Test the case where preferred resolution is supported. List filteredSizes = resolutionFilter.filter(fakeSupportedSizes, 90); assertEquals(filteredSizes.get(0), preferredSize); - // Test case where preferred resolution is not supported. + // Test the case where preferred resolution is not supported. fakeSupportedSizes.remove(0); filteredSizes = resolutionFilter.filter(fakeSupportedSizes, 90); assertEquals(filteredSizes, fakeSupportedSizes); diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionSelectorTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionSelectorTest.java index a42887ea1b0..0f45f07b4f7 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionSelectorTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionSelectorTest.java @@ -43,14 +43,14 @@ public void hostApiCreate_createsExpectedResolutionSelectorInstance() { final long resolutionStrategyIdentifier = 14; instanceManager.addDartCreatedInstance(mockResolutionStrategy, resolutionStrategyIdentifier); - final ResolutionFilter mockResolutionFilter = mock(ResolutionFilter.class); - final long resolutionFilterIdentifier = 33; - instanceManager.addDartCreatedInstance(mockResolutionFilter, resolutionFilterIdentifier); - final AspectRatioStrategy mockAspectRatioStrategy = mock(AspectRatioStrategy.class); final long aspectRatioStrategyIdentifier = 15; instanceManager.addDartCreatedInstance(mockAspectRatioStrategy, aspectRatioStrategyIdentifier); + final ResolutionFilter mockResolutionFilter = mock(ResolutionFilter.class); + final long resolutionFilterIdentifier = 33; + instanceManager.addDartCreatedInstance(mockResolutionFilter, resolutionFilterIdentifier); + when(mockProxy.create(mockResolutionStrategy, mockAspectRatioStrategy, mockResolutionFilter)) .thenReturn(mockResolutionSelector); final ResolutionSelectorHostApiImpl hostApi = diff --git a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart index 14ec3823dcf..6fec50ce398 100644 --- a/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart +++ b/packages/camera/camera_android_camerax/lib/src/camerax_proxy.dart @@ -179,7 +179,7 @@ class CameraXProxy { AspectRatioStrategy Function(int aspectRatio, int fallbackRule) createAspectRatioStrategy; - /// Creates [ResolutionFilter] that prioritizes specified resolution. + /// Creates a [ResolutionFilter] that prioritizes specified resolution. ResolutionFilter Function(Size preferredResolution) createResolutionFilterWithOnePreferredSize; diff --git a/packages/camera/camera_android_camerax/lib/src/resolution_filter.dart b/packages/camera/camera_android_camerax/lib/src/resolution_filter.dart index bfec288356a..cc7d1114930 100644 --- a/packages/camera/camera_android_camerax/lib/src/resolution_filter.dart +++ b/packages/camera/camera_android_camerax/lib/src/resolution_filter.dart @@ -9,24 +9,27 @@ import 'camerax_library.g.dart'; import 'instance_manager.dart'; import 'java_object.dart'; -/// Filter/sorter for applications to specify preferred resolutions. +/// Filter for applications to specify preferred resolutions. /// /// This is an indirect wrapping of the native Android `ResolutionFilter`, -/// which is an interface that requires a synchronous response, which is not -/// possible through pigeon. Thus, constructing a [ResolutionFilter] will create -/// a native `ResolutionFilter` with the characteristics as described below. If -/// these constructors do not meet your needs, feel free to add a new +/// an interface that requires a synchronous response. Achieving such is not +/// possible through pigeon. Thus, constructing a [ResolutionFilter] with a +/// particular constructor will create a native `ResolutionFilter` with the +/// characteristics described in the documentation for that constructor, +/// respectively. +/// +/// If the provided constructors do not meet your needs, feel free to add a new /// constructor; see CONTRIBUTING.MD for more information on how to do so. /// /// See https://developer.android.com/reference/androidx/camera/core/ResolutionFilter/ResolutionFilter. @immutable class ResolutionFilter extends JavaObject { - /// Construct a [ResolutionFilter]. + /// Constructs a [ResolutionFilter]. /// - /// Because this is an indirect wrapping of the native `ResolutionFilter`, - /// this will construct a filter that will only prioritize the specified - /// [preferredResolution] over the other resolutions, whose order of - /// preference (according to CameraX) will remain the same. + /// This will construct a native `ResolutionFilter` that will prioritize the + /// specified [preferredResolution] (if supported) over other supported + /// resolutions, whose priorities (as determined by CameraX) will remain the + /// same. ResolutionFilter.onePreferredSize({ required this.preferredResolution, super.binaryMessenger, @@ -53,7 +56,7 @@ class ResolutionFilter extends JavaObject { final _ResolutionFilterHostApiImpl _api; - /// The resolution for the filter to prioritize. + /// The resolution for a [ResolutionFilter.onePreferredSize] to prioritize. final Size preferredResolution; } diff --git a/packages/camera/camera_android_camerax/test/resolution_filter_test.dart b/packages/camera/camera_android_camerax/test/resolution_filter_test.dart index 3011cf0f455..07a96ff6802 100644 --- a/packages/camera/camera_android_camerax/test/resolution_filter_test.dart +++ b/packages/camera/camera_android_camerax/test/resolution_filter_test.dart @@ -58,8 +58,7 @@ void main() { )); }); - test( - 'HostApi createWithOnePreferredSize creates expected ResolutionStrategy', + test('HostApi createWithOnePreferredSize creates expected ResolutionFilter', () { final MockTestResolutionFilterHostApi mockApi = MockTestResolutionFilterHostApi(); From 29a77d5fb564ca17858d8358abb3988d9d44e4e0 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Wed, 27 Mar 2024 09:45:46 -0700 Subject: [PATCH 10/10] Address review --- .../camerax/ResolutionFilterHostApiImpl.java | 24 ++++++++++++------- .../plugins/camerax/ResolutionFilterTest.java | 1 - .../lib/src/resolution_filter.dart | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java index 8601ece52d7..b2c3c9e6912 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ResolutionFilterHostApiImpl.java @@ -20,14 +20,20 @@ */ public class ResolutionFilterHostApiImpl implements ResolutionFilterHostApi { private final InstanceManager instanceManager; - private final ResolutionFilterProxy proxy; + private final ResolutionFilterFactory resolutionFilterFactory; - /** Proxy for constructor of {@link ResolutionFilter}. */ + /** + * Proxy for constructing {@link ResolutionFilter}s with particular attributes, as detailed by + * documentation below. + */ @VisibleForTesting - public static class ResolutionFilterProxy { + public static class ResolutionFilterFactory { /** * Creates an instance of {@link ResolutionFilter} that moves the {@code preferredSize} to the * front of the list of supported resolutions so that it can be prioritized by CameraX. + * + *

If the preferred {@code Size} is not found, then this creates a {@link ResolutionFilter} + * that leaves the priority of supported resolutions unadjusted. */ @NonNull public ResolutionFilter createWithOnePreferredSize(@NonNull Size preferredSize) { @@ -54,20 +60,22 @@ public List filter(@NonNull List supportedSizes, int rotationDegrees * @param instanceManager maintains instances stored to communicate with attached Dart objects */ public ResolutionFilterHostApiImpl(@NonNull InstanceManager instanceManager) { - this(instanceManager, new ResolutionFilterProxy()); + this(instanceManager, new ResolutionFilterFactory()); } /** * Constructs a {@link ResolutionFilterHostApiImpl}. * * @param instanceManager maintains instances stored to communicate with attached Dart objects - * @param proxy proxy for constructor of {@link ResolutionFilter} + * @param resolutionFilterFactory proxy for constructing different kinds of {@link + * ResolutionFilter}s */ @VisibleForTesting ResolutionFilterHostApiImpl( - @NonNull InstanceManager instanceManager, @NonNull ResolutionFilterProxy proxy) { + @NonNull InstanceManager instanceManager, + @NonNull ResolutionFilterFactory resolutionFilterFactory) { this.instanceManager = instanceManager; - this.proxy = proxy; + this.resolutionFilterFactory = resolutionFilterFactory; } /** @@ -81,6 +89,6 @@ public void createWithOnePreferredSize( new Size( preferredResolution.getWidth().intValue(), preferredResolution.getHeight().intValue()); instanceManager.addDartCreatedInstance( - proxy.createWithOnePreferredSize(preferredSize), identifier); + resolutionFilterFactory.createWithOnePreferredSize(preferredSize), identifier); } } diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java index 7e086d938d4..150f5676739 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ResolutionFilterTest.java @@ -16,7 +16,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; diff --git a/packages/camera/camera_android_camerax/lib/src/resolution_filter.dart b/packages/camera/camera_android_camerax/lib/src/resolution_filter.dart index cc7d1114930..3a428a00e73 100644 --- a/packages/camera/camera_android_camerax/lib/src/resolution_filter.dart +++ b/packages/camera/camera_android_camerax/lib/src/resolution_filter.dart @@ -9,7 +9,7 @@ import 'camerax_library.g.dart'; import 'instance_manager.dart'; import 'java_object.dart'; -/// Filter for applications to specify preferred resolutions. +/// Filterer for applications to specify preferred resolutions. /// /// This is an indirect wrapping of the native Android `ResolutionFilter`, /// an interface that requires a synchronous response. Achieving such is not