From baeabd0f92d5f7476b2b39c2de582b2f08674526 Mon Sep 17 00:00:00 2001 From: "J. Lee Coltrane" Date: Sun, 21 Sep 2025 15:42:25 -0400 Subject: [PATCH] [camera_avfoundation] Return accurate values for lensType on ios Previously, lensType was always .unknown on iOS. This CL implements a mapping from the platform's AVCaptureDevice.DeviceType to our more generic CameraLensType. [camera_avfoundation] bump min version of camera_platform_interface to 2.10.0 These changes depend on the CameraLensType that was added to camera_platform_interface in version 2.10.0. [camera] revert overrides in base camera package [camera_avfoundation] bump package version to 0.9.21+5 --- .../camera/camera_avfoundation/CHANGELOG.md | 4 + .../RunnerTests/AvailableCamerasTests.swift | 84 +++++++++++-------- .../RunnerTests/Mocks/MockCaptureDevice.swift | 1 + .../camera_avfoundation/CameraPlugin.swift | 16 +++- .../FLTCaptureDevice.m | 5 ++ .../camera_avfoundation/FLTCaptureDevice.h | 3 + .../include/camera_avfoundation/messages.g.h | 19 ++++- .../camera_avfoundation_objc/messages.g.m | 49 ++++++++--- .../lib/src/messages.g.dart | 44 +++++++--- .../camera_avfoundation/lib/src/utils.dart | 11 +++ .../camera_avfoundation/pigeons/messages.dart | 15 +++- .../camera/camera_avfoundation/pubspec.yaml | 4 +- .../test/avfoundation_camera_test.dart | 6 ++ .../camera_avfoundation/test/utils_test.dart | 29 +++++++ 14 files changed, 224 insertions(+), 66 deletions(-) diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 797d053b5e2d..bbbb812ee6c4 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.21+5 + +* Adds accurate values for `lensType` in `CameraDescription`. + ## 0.9.21+4 * Migrates `updateOrientation` and `setCaptureSessionPreset` methods to Swift. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift index 50eb2f62ab16..fa76be601e99 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTests.swift @@ -28,38 +28,62 @@ final class AvailableCamerasTest: XCTestCase { ) } + private func fakeNativeCameraList() -> [MockCaptureDevice] { + var cameras: [MockCaptureDevice] = [] + + let wideAngleCamera = MockCaptureDevice() + wideAngleCamera.uniqueID = "0" + wideAngleCamera.position = .back + wideAngleCamera.deviceType = .builtInWideAngleCamera + + let frontFacingCamera = MockCaptureDevice() + frontFacingCamera.uniqueID = "1" + frontFacingCamera.position = .front + frontFacingCamera.deviceType = .builtInWideAngleCamera + + let ultraWideCamera = MockCaptureDevice() + ultraWideCamera.uniqueID = "2" + ultraWideCamera.position = .back + ultraWideCamera.deviceType = .builtInUltraWideCamera + + let telephotoCamera = MockCaptureDevice() + telephotoCamera.uniqueID = "3" + telephotoCamera.position = .back + telephotoCamera.deviceType = .builtInTelephotoCamera + + // the order of `cameras` is important. It must match the order of the + // discoveryDevices list used by availableCameras() + cameras = [ + wideAngleCamera, frontFacingCamera, telephotoCamera, ultraWideCamera, + ] + + return cameras + } + func testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone() { let mockDeviceDiscoverer = MockCameraDeviceDiscoverer() let cameraPlugin = createCameraPlugin(with: mockDeviceDiscoverer) let expectation = self.expectation(description: "Result finished") - mockDeviceDiscoverer.discoverySessionStub = { deviceTypes, mediaType, position in - // iPhone 13 Cameras: - let wideAngleCamera = MockCaptureDevice() - wideAngleCamera.uniqueID = "0" - wideAngleCamera.position = .back - - let frontFacingCamera = MockCaptureDevice() - frontFacingCamera.uniqueID = "1" - frontFacingCamera.position = .front - - let ultraWideCamera = MockCaptureDevice() - ultraWideCamera.uniqueID = "2" - ultraWideCamera.position = .back - - let telephotoCamera = MockCaptureDevice() - telephotoCamera.uniqueID = "3" - telephotoCamera.position = .back + // We'll stub the discovery session and return this list of fake cameras + let nativeCameras = fakeNativeCameraList() - var requiredTypes: [AVCaptureDevice.DeviceType] = [ - .builtInWideAngleCamera, .builtInTelephotoCamera, .builtInUltraWideCamera, - ] - var cameras = [wideAngleCamera, frontFacingCamera, telephotoCamera, ultraWideCamera] + // The order of expectedDeviceTypesToBeRequested is important. We will use + // this in our discovery session stub to confirm that availableCameras() + // requests the correct DeviceTypes in the correct order. + var expectedDeviceTypesToBeRequested: [AVCaptureDevice.DeviceType] = [ + .builtInWideAngleCamera, + .builtInTelephotoCamera, + .builtInUltraWideCamera, + ] - XCTAssertEqual(deviceTypes, requiredTypes) + mockDeviceDiscoverer.discoverySessionStub = { deviceTypes, mediaType, position in + // confirm that availableCameras() made the + // expected call to our discovery stub + XCTAssertEqual(deviceTypes, expectedDeviceTypesToBeRequested) XCTAssertEqual(mediaType, .video) XCTAssertEqual(position, .unspecified) - return cameras + return nativeCameras } var resultValue: [FCPPlatformCameraDescription]? @@ -71,7 +95,7 @@ final class AvailableCamerasTest: XCTestCase { waitForExpectations(timeout: 30, handler: nil) // Verify the result. - XCTAssertEqual(resultValue?.count, 4) + XCTAssertEqual(resultValue?.count, nativeCameras.count) } func testAvailableCamerasShouldReturnTwoCamerasOnDualCameraIPhone() { @@ -89,14 +113,8 @@ final class AvailableCamerasTest: XCTestCase { frontFacingCamera.uniqueID = "1" frontFacingCamera.position = .front - var requiredTypes: [AVCaptureDevice.DeviceType] = [ - .builtInWideAngleCamera, .builtInTelephotoCamera, .builtInUltraWideCamera, - ] let cameras = [wideAngleCamera, frontFacingCamera] - XCTAssertEqual(deviceTypes, requiredTypes) - XCTAssertEqual(mediaType, .video) - XCTAssertEqual(position, .unspecified) return cameras } @@ -122,14 +140,8 @@ final class AvailableCamerasTest: XCTestCase { unspecifiedCamera.uniqueID = "0" unspecifiedCamera.position = .unspecified - var requiredTypes: [AVCaptureDevice.DeviceType] = [ - .builtInWideAngleCamera, .builtInTelephotoCamera, .builtInUltraWideCamera, - ] let cameras = [unspecifiedCamera] - XCTAssertEqual(deviceTypes, requiredTypes) - XCTAssertEqual(mediaType, .video) - XCTAssertEqual(position, .unspecified) return cameras } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift index b294b1e3e1c5..64ab36e43e07 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.swift @@ -32,6 +32,7 @@ class MockCaptureDevice: NSObject, FLTCaptureDevice { var uniqueID = "" var position = AVCaptureDevice.Position.unspecified + var deviceType = AVCaptureDevice.DeviceType.builtInWideAngleCamera var activeFormat: FLTCaptureDeviceFormat { get { diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.swift b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.swift index a6029e5436c7..0ef95cf68d5e 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.swift +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.swift @@ -158,9 +158,23 @@ extension CameraPlugin: FCPCameraApi { lensFacing = .external } + var lensType: FCPPlatformCameraLensType + + switch device.deviceType { + case .builtInWideAngleCamera: + lensType = .builtInWideAngleCamera + case .builtInTelephotoCamera: + lensType = .builtInTelephotoCamera + case .builtInUltraWideCamera: + lensType = .builtInUltraWideCamera + default: + lensType = .unknown + } + let cameraDescription = FCPPlatformCameraDescription.make( withName: device.uniqueID, - lensDirection: lensFacing + lensDirection: lensFacing, + lensType: lensType ) reply.append(cameraDescription) } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/FLTCaptureDevice.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/FLTCaptureDevice.m index 68f486f91f45..20d659f121e4 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/FLTCaptureDevice.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/FLTCaptureDevice.m @@ -30,6 +30,11 @@ - (AVCaptureDevicePosition)position { return self.device.position; } +// lens type +- (AVCaptureDeviceType)deviceType { + return self.device.deviceType; +} + // Format/Configuration - (NSObject *)activeFormat { return [[FLTDefaultCaptureDeviceFormat alloc] initWithFormat:self.device.activeFormat]; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCaptureDevice.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCaptureDevice.h index 3244e70fc737..328a54613510 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCaptureDevice.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/FLTCaptureDevice.h @@ -24,6 +24,9 @@ NS_ASSUME_NONNULL_BEGIN // Position/Orientation @property(nonatomic, readonly) AVCaptureDevicePosition position; +// Device type +@property(nonatomic, readonly) AVCaptureDeviceType deviceType; + // Format/Configuration @property(nonatomic, retain) NSObject *activeFormat; @property(nonatomic, readonly) NSArray *> *formats; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/messages.g.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/messages.g.h index 23e4fb772461..81379f3c542a 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/messages.g.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/include/camera_avfoundation/messages.g.h @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v22.4.2), do not edit directly. +// Autogenerated from Pigeon (v22.7.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #import @@ -114,6 +114,19 @@ typedef NS_ENUM(NSUInteger, FCPPlatformResolutionPreset) { - (instancetype)initWithValue:(FCPPlatformResolutionPreset)value; @end +typedef NS_ENUM(NSUInteger, FCPPlatformCameraLensType) { + FCPPlatformCameraLensTypeBuiltInWideAngleCamera = 0, + FCPPlatformCameraLensTypeBuiltInUltraWideCamera = 1, + FCPPlatformCameraLensTypeBuiltInTelephotoCamera = 2, + FCPPlatformCameraLensTypeUnknown = 3, +}; + +/// Wrapper for FCPPlatformCameraLensType to allow for nullability. +@interface FCPPlatformCameraLensTypeBox : NSObject +@property(nonatomic, assign) FCPPlatformCameraLensType value; +- (instancetype)initWithValue:(FCPPlatformCameraLensType)value; +@end + @class FCPPlatformCameraDescription; @class FCPPlatformCameraState; @class FCPPlatformMediaSettings; @@ -124,11 +137,13 @@ typedef NS_ENUM(NSUInteger, FCPPlatformResolutionPreset) { /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; + (instancetype)makeWithName:(NSString *)name - lensDirection:(FCPPlatformCameraLensDirection)lensDirection; + lensDirection:(FCPPlatformCameraLensDirection)lensDirection + lensType:(FCPPlatformCameraLensType)lensType; /// The name of the camera device. @property(nonatomic, copy) NSString *name; /// The direction the camera is facing. @property(nonatomic, assign) FCPPlatformCameraLensDirection lensDirection; +@property(nonatomic, assign) FCPPlatformCameraLensType lensType; @end @interface FCPPlatformCameraState : NSObject diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/messages.g.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/messages.g.m index f0543adc6c43..4fcf06763673 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/messages.g.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation_objc/messages.g.m @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v22.4.2), do not edit directly. +// Autogenerated from Pigeon (v22.7.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #import "./include/camera_avfoundation/messages.g.h" @@ -120,6 +120,16 @@ - (instancetype)initWithValue:(FCPPlatformResolutionPreset)value { } @end +@implementation FCPPlatformCameraLensTypeBox +- (instancetype)initWithValue:(FCPPlatformCameraLensType)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + @interface FCPPlatformCameraDescription () + (FCPPlatformCameraDescription *)fromList:(NSArray *)list; + (nullable FCPPlatformCameraDescription *)nullableFromList:(NSArray *)list; @@ -152,10 +162,12 @@ + (nullable FCPPlatformSize *)nullableFromList:(NSArray *)list; @implementation FCPPlatformCameraDescription + (instancetype)makeWithName:(NSString *)name - lensDirection:(FCPPlatformCameraLensDirection)lensDirection { + lensDirection:(FCPPlatformCameraLensDirection)lensDirection + lensType:(FCPPlatformCameraLensType)lensType { FCPPlatformCameraDescription *pigeonResult = [[FCPPlatformCameraDescription alloc] init]; pigeonResult.name = name; pigeonResult.lensDirection = lensDirection; + pigeonResult.lensType = lensType; return pigeonResult; } + (FCPPlatformCameraDescription *)fromList:(NSArray *)list { @@ -164,6 +176,8 @@ + (FCPPlatformCameraDescription *)fromList:(NSArray *)list { FCPPlatformCameraLensDirectionBox *boxedFCPPlatformCameraLensDirection = GetNullableObjectAtIndex(list, 1); pigeonResult.lensDirection = boxedFCPPlatformCameraLensDirection.value; + FCPPlatformCameraLensTypeBox *boxedFCPPlatformCameraLensType = GetNullableObjectAtIndex(list, 2); + pigeonResult.lensType = boxedFCPPlatformCameraLensType.value; return pigeonResult; } + (nullable FCPPlatformCameraDescription *)nullableFromList:(NSArray *)list { @@ -173,6 +187,7 @@ + (nullable FCPPlatformCameraDescription *)nullableFromList:(NSArray *)list return @[ self.name ?: [NSNull null], [[FCPPlatformCameraLensDirectionBox alloc] initWithValue:self.lensDirection], + [[FCPPlatformCameraLensTypeBox alloc] initWithValue:self.lensType], ]; } @end @@ -356,15 +371,21 @@ - (nullable id)readValueOfType:(UInt8)type { : [[FCPPlatformResolutionPresetBox alloc] initWithValue:[enumAsNumber integerValue]]; } - case 137: - return [FCPPlatformCameraDescription fromList:[self readValue]]; + case 137: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil + ? nil + : [[FCPPlatformCameraLensTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; + } case 138: - return [FCPPlatformCameraState fromList:[self readValue]]; + return [FCPPlatformCameraDescription fromList:[self readValue]]; case 139: - return [FCPPlatformMediaSettings fromList:[self readValue]]; + return [FCPPlatformCameraState fromList:[self readValue]]; case 140: - return [FCPPlatformPoint fromList:[self readValue]]; + return [FCPPlatformMediaSettings fromList:[self readValue]]; case 141: + return [FCPPlatformPoint fromList:[self readValue]]; + case 142: return [FCPPlatformSize fromList:[self readValue]]; default: return [super readValueOfType:type]; @@ -408,20 +429,24 @@ - (void)writeValue:(id)value { FCPPlatformResolutionPresetBox *box = (FCPPlatformResolutionPresetBox *)value; [self writeByte:136]; [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; - } else if ([value isKindOfClass:[FCPPlatformCameraDescription class]]) { + } else if ([value isKindOfClass:[FCPPlatformCameraLensTypeBox class]]) { + FCPPlatformCameraLensTypeBox *box = (FCPPlatformCameraLensTypeBox *)value; [self writeByte:137]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FCPPlatformCameraDescription class]]) { + [self writeByte:138]; [self writeValue:[value toList]]; } else if ([value isKindOfClass:[FCPPlatformCameraState class]]) { - [self writeByte:138]; + [self writeByte:139]; [self writeValue:[value toList]]; } else if ([value isKindOfClass:[FCPPlatformMediaSettings class]]) { - [self writeByte:139]; + [self writeByte:140]; [self writeValue:[value toList]]; } else if ([value isKindOfClass:[FCPPlatformPoint class]]) { - [self writeByte:140]; + [self writeByte:141]; [self writeValue:[value toList]]; } else if ([value isKindOfClass:[FCPPlatformSize class]]) { - [self writeByte:141]; + [self writeByte:142]; [self writeValue:[value toList]]; } else { [super writeValue:value]; diff --git a/packages/camera/camera_avfoundation/lib/src/messages.g.dart b/packages/camera/camera_avfoundation/lib/src/messages.g.dart index f771611beabd..a263e19218a7 100644 --- a/packages/camera/camera_avfoundation/lib/src/messages.g.dart +++ b/packages/camera/camera_avfoundation/lib/src/messages.g.dart @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v22.4.2), do not edit directly. +// Autogenerated from Pigeon (v22.7.4), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers @@ -63,8 +63,19 @@ enum PlatformImageFormatGroup { bgra8888, yuv420 } enum PlatformResolutionPreset { low, medium, high, veryHigh, ultraHigh, max } +enum PlatformCameraLensType { + builtInWideAngleCamera, + builtInUltraWideCamera, + builtInTelephotoCamera, + unknown, +} + class PlatformCameraDescription { - PlatformCameraDescription({required this.name, required this.lensDirection}); + PlatformCameraDescription({ + required this.name, + required this.lensDirection, + required this.lensType, + }); /// The name of the camera device. String name; @@ -72,8 +83,10 @@ class PlatformCameraDescription { /// The direction the camera is facing. PlatformCameraLensDirection lensDirection; + PlatformCameraLensType lensType; + Object encode() { - return [name, lensDirection]; + return [name, lensDirection, lensType]; } static PlatformCameraDescription decode(Object result) { @@ -81,6 +94,7 @@ class PlatformCameraDescription { return PlatformCameraDescription( name: result[0]! as String, lensDirection: result[1]! as PlatformCameraLensDirection, + lensType: result[2]! as PlatformCameraLensType, ); } } @@ -240,20 +254,23 @@ class _PigeonCodec extends StandardMessageCodec { } else if (value is PlatformResolutionPreset) { buffer.putUint8(136); writeValue(buffer, value.index); - } else if (value is PlatformCameraDescription) { + } else if (value is PlatformCameraLensType) { buffer.putUint8(137); + writeValue(buffer, value.index); + } else if (value is PlatformCameraDescription) { + buffer.putUint8(138); writeValue(buffer, value.encode()); } else if (value is PlatformCameraState) { - buffer.putUint8(138); + buffer.putUint8(139); writeValue(buffer, value.encode()); } else if (value is PlatformMediaSettings) { - buffer.putUint8(139); + buffer.putUint8(140); writeValue(buffer, value.encode()); } else if (value is PlatformPoint) { - buffer.putUint8(140); + buffer.putUint8(141); writeValue(buffer, value.encode()); } else if (value is PlatformSize) { - buffer.putUint8(141); + buffer.putUint8(142); writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); @@ -288,14 +305,17 @@ class _PigeonCodec extends StandardMessageCodec { final int? value = readValue(buffer) as int?; return value == null ? null : PlatformResolutionPreset.values[value]; case 137: - return PlatformCameraDescription.decode(readValue(buffer)!); + final int? value = readValue(buffer) as int?; + return value == null ? null : PlatformCameraLensType.values[value]; case 138: - return PlatformCameraState.decode(readValue(buffer)!); + return PlatformCameraDescription.decode(readValue(buffer)!); case 139: - return PlatformMediaSettings.decode(readValue(buffer)!); + return PlatformCameraState.decode(readValue(buffer)!); case 140: - return PlatformPoint.decode(readValue(buffer)!); + return PlatformMediaSettings.decode(readValue(buffer)!); case 141: + return PlatformPoint.decode(readValue(buffer)!); + case 142: return PlatformSize.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); diff --git a/packages/camera/camera_avfoundation/lib/src/utils.dart b/packages/camera/camera_avfoundation/lib/src/utils.dart index 80cdc2e5e48c..4fdfcf8adffe 100644 --- a/packages/camera/camera_avfoundation/lib/src/utils.dart +++ b/packages/camera/camera_avfoundation/lib/src/utils.dart @@ -15,9 +15,20 @@ CameraDescription cameraDescriptionFromPlatform( name: camera.name, lensDirection: cameraLensDirectionFromPlatform(camera.lensDirection), sensorOrientation: 90, + lensType: cameraLensTypeFromPlatform(camera.lensType), ); } +/// Converts a Pigeon [PlatformCameraLensType] to a [CameraLensType]. +CameraLensType cameraLensTypeFromPlatform(PlatformCameraLensType lensType) { + return switch (lensType) { + PlatformCameraLensType.builtInWideAngleCamera => CameraLensType.wide, + PlatformCameraLensType.builtInUltraWideCamera => CameraLensType.ultraWide, + PlatformCameraLensType.builtInTelephotoCamera => CameraLensType.telephoto, + PlatformCameraLensType.unknown => CameraLensType.unknown, + }; +} + /// Converts a Pigeon [PlatformCameraLensDirection] to a [CameraLensDirection]. CameraLensDirection cameraLensDirectionFromPlatform( PlatformCameraLensDirection direction, diff --git a/packages/camera/camera_avfoundation/pigeons/messages.dart b/packages/camera/camera_avfoundation/pigeons/messages.dart index 4427fa285673..03fff874986e 100644 --- a/packages/camera/camera_avfoundation/pigeons/messages.dart +++ b/packages/camera/camera_avfoundation/pigeons/messages.dart @@ -56,15 +56,28 @@ enum PlatformImageFormatGroup { bgra8888, yuv420 } // Pigeon version of ResolutionPreset. enum PlatformResolutionPreset { low, medium, high, veryHigh, ultraHigh, max } +enum PlatformCameraLensType { + builtInWideAngleCamera, + builtInUltraWideCamera, + builtInTelephotoCamera, + unknown, +} + // Pigeon version of CameraDescription. class PlatformCameraDescription { - PlatformCameraDescription({required this.name, required this.lensDirection}); + PlatformCameraDescription({ + required this.name, + required this.lensDirection, + required this.lensType, + }); /// The name of the camera device. final String name; /// The direction the camera is facing. final PlatformCameraLensDirection lensDirection; + + final PlatformCameraLensType lensType; } // Pigeon version of the data needed for a CameraInitializedEvent. diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index 4603ead66599..a7ab2e691c36 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.21+4 +version: 0.9.21+5 environment: sdk: ^3.9.0 @@ -17,7 +17,7 @@ flutter: dartPluginClass: AVFoundationCamera dependencies: - camera_platform_interface: ^2.9.0 + camera_platform_interface: ^2.10.0 flutter: sdk: flutter stream_transform: ^2.0.0 diff --git a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart index 6a5044228994..e21c618a5b58 100644 --- a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart +++ b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart @@ -407,10 +407,12 @@ void main() { PlatformCameraDescription( name: 'Test 1', lensDirection: PlatformCameraLensDirection.front, + lensType: PlatformCameraLensType.builtInWideAngleCamera, ), PlatformCameraDescription( name: 'Test 2', lensDirection: PlatformCameraLensDirection.back, + lensType: PlatformCameraLensType.builtInUltraWideCamera, ), ]; when(mockApi.getAvailableCameras()).thenAnswer((_) async => returnData); @@ -426,6 +428,10 @@ void main() { ); // This value isn't provided by the platform, so is hard-coded to 90. expect(cameras[i].sensorOrientation, 90); + expect( + cameras[i].lensType, + cameraLensTypeFromPlatform(returnData[i].lensType), + ); } }, ); diff --git a/packages/camera/camera_avfoundation/test/utils_test.dart b/packages/camera/camera_avfoundation/test/utils_test.dart index 6733a34f6951..ae4e5e616ed9 100644 --- a/packages/camera/camera_avfoundation/test/utils_test.dart +++ b/packages/camera/camera_avfoundation/test/utils_test.dart @@ -10,6 +10,35 @@ import 'package:flutter_test/flutter_test.dart'; void main() { group('Utility methods', () { + test('Should convert CameraLensType values correctly', () { + expect( + cameraLensTypeFromPlatform( + PlatformCameraLensType.builtInWideAngleCamera, + ), + CameraLensType.wide, + reason: 'PlatformLensType.builtInWideAngleCamera', + ); + expect( + cameraLensTypeFromPlatform( + PlatformCameraLensType.builtInUltraWideCamera, + ), + CameraLensType.ultraWide, + reason: 'PlatformLensType.builtInUltraWideCamera', + ); + expect( + cameraLensTypeFromPlatform( + PlatformCameraLensType.builtInTelephotoCamera, + ), + CameraLensType.telephoto, + reason: 'PlatformLensType.builtInTelephotoCamera', + ); + expect( + cameraLensTypeFromPlatform(PlatformCameraLensType.unknown), + CameraLensType.unknown, + reason: 'PlatformLensType.unknown', + ); + }); + test('Should convert CameraLensDirection values correctly', () { expect( cameraLensDirectionFromPlatform(PlatformCameraLensDirection.back),