Skip to content

Commit 0152717

Browse files
[camera] Fix iOS torch mode regression (flutter#7085)
Fixes a regression from the Pigeon conversion, where converting from a Pigeon flash mode to an OS flash mode now fails instead of returning a magic sentinel value, so the logic to handle it needed to be adjusted, but wasn't in the conversion. Fixes flutter#151453
1 parent 4063b20 commit 0152717

File tree

7 files changed

+77
-13
lines changed

7 files changed

+77
-13
lines changed

packages/camera/camera_avfoundation/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.9.16+2
2+
3+
* Fixes regression taking a picture in torch mode.
4+
15
## 0.9.16+1
26

37
* Fixes sample times not being numeric after pause/resume.

packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ - (void)testSettings_shouldPassConfigurationToCameraDeviceAndWriter {
142142
[[TestMediaSettingsAVWrapper alloc] initWithTestCase:self];
143143

144144
FLTCam *camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings(
145-
dispatch_queue_create("test", NULL), settings, injectedWrapper);
145+
dispatch_queue_create("test", NULL), settings, injectedWrapper, nil);
146146

147147
// Expect FPS configuration is passed to camera device.
148148
[self waitForExpectations:@[

packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ NS_ASSUME_NONNULL_BEGIN
1212
/// @param mediaSettings media settings configuration parameters
1313
/// @param mediaSettingsAVWrapper provider to perform media settings operations (for unit test
1414
/// dependency injection).
15+
/// @param captureDeviceFactory a callback to create capture device instances
1516
/// @return an FLTCam object.
1617
extern FLTCam *_Nullable FLTCreateCamWithCaptureSessionQueueAndMediaSettings(
1718
dispatch_queue_t _Nullable captureSessionQueue,
1819
FCPPlatformMediaSettings *_Nullable mediaSettings,
19-
FLTCamMediaSettingsAVWrapper *_Nullable mediaSettingsAVWrapper);
20+
FLTCamMediaSettingsAVWrapper *_Nullable mediaSettingsAVWrapper,
21+
CaptureDeviceFactory _Nullable captureDeviceFactory);
2022

2123
extern FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessionQueue);
2224

packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
}
1919

2020
FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessionQueue) {
21-
return FLTCreateCamWithCaptureSessionQueueAndMediaSettings(captureSessionQueue, nil, nil);
21+
return FLTCreateCamWithCaptureSessionQueueAndMediaSettings(captureSessionQueue, nil, nil, nil);
2222
}
2323

2424
FLTCam *FLTCreateCamWithCaptureSessionQueueAndMediaSettings(
2525
dispatch_queue_t captureSessionQueue, FCPPlatformMediaSettings *mediaSettings,
26-
FLTCamMediaSettingsAVWrapper *mediaSettingsAVWrapper) {
26+
FLTCamMediaSettingsAVWrapper *mediaSettingsAVWrapper,
27+
CaptureDeviceFactory captureDeviceFactory) {
2728
if (!mediaSettings) {
2829
mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMedium);
2930
}
@@ -51,14 +52,19 @@
5152
OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]);
5253
OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES);
5354

54-
id fltCam = [[FLTCam alloc] initWithCameraName:@"camera"
55-
mediaSettings:mediaSettings
56-
mediaSettingsAVWrapper:mediaSettingsAVWrapper
57-
orientation:UIDeviceOrientationPortrait
55+
id fltCam = [[FLTCam alloc] initWithMediaSettings:mediaSettings
56+
mediaSettingsAVWrapper:mediaSettingsAVWrapper
57+
orientation:UIDeviceOrientationPortrait
5858
videoCaptureSession:videoSessionMock
5959
audioCaptureSession:audioSessionMock
6060
captureSessionQueue:captureSessionQueue
61-
error:nil];
61+
captureDeviceFactory:captureDeviceFactory ?: ^AVCaptureDevice *(void) {
62+
return [AVCaptureDevice deviceWithUniqueID:@"camera"];
63+
}
64+
videoDimensionsForFormat:^CMVideoDimensions(AVCaptureDeviceFormat *format) {
65+
return CMVideoFormatDescriptionGetDimensions(format.formatDescription);
66+
}
67+
error:nil];
6268

6369
id captureVideoDataOutputMock = [OCMockObject niceMockForClass:[AVCaptureVideoDataOutput class]];
6470

packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,56 @@ - (void)testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndF
169169
});
170170
[self waitForExpectationsWithTimeout:1 handler:nil];
171171
}
172+
173+
- (void)testCaptureToFile_handlesTorchMode {
174+
XCTestExpectation *pathExpectation =
175+
[self expectationWithDescription:
176+
@"Must send file path to result if save photo delegate completes with file path."];
177+
178+
id captureDeviceMock = OCMClassMock([AVCaptureDevice class]);
179+
OCMStub([captureDeviceMock hasTorch]).andReturn(YES);
180+
OCMStub([captureDeviceMock isTorchAvailable]).andReturn(YES);
181+
OCMStub([captureDeviceMock torchMode]).andReturn(AVCaptureTorchModeAuto);
182+
OCMExpect([captureDeviceMock setTorchMode:AVCaptureTorchModeOn]);
183+
184+
dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL);
185+
dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific,
186+
(void *)FLTCaptureSessionQueueSpecific, NULL);
187+
188+
FLTCam *cam = FLTCreateCamWithCaptureSessionQueueAndMediaSettings(captureSessionQueue, nil, nil,
189+
^AVCaptureDevice *(void) {
190+
return captureDeviceMock;
191+
});
192+
193+
AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings];
194+
id mockSettings = OCMClassMock([AVCapturePhotoSettings class]);
195+
OCMStub([mockSettings photoSettings]).andReturn(settings);
196+
197+
NSString *filePath = @"test";
198+
199+
id mockOutput = OCMClassMock([AVCapturePhotoOutput class]);
200+
OCMStub([mockOutput capturePhotoWithSettings:OCMOCK_ANY delegate:OCMOCK_ANY])
201+
.andDo(^(NSInvocation *invocation) {
202+
FLTSavePhotoDelegate *delegate = cam.inProgressSavePhotoDelegates[@(settings.uniqueID)];
203+
// Completion runs on IO queue.
204+
dispatch_queue_t ioQueue = dispatch_queue_create("io_queue", NULL);
205+
dispatch_async(ioQueue, ^{
206+
delegate.completionHandler(filePath, nil);
207+
});
208+
});
209+
cam.capturePhotoOutput = mockOutput;
210+
211+
// `FLTCam::captureToFile` runs on capture session queue.
212+
dispatch_async(captureSessionQueue, ^{
213+
[cam setFlashMode:FCPPlatformFlashModeTorch
214+
withCompletion:^(FlutterError *_){
215+
}];
216+
[cam captureToFileWithCompletion:^(NSString *result, FlutterError *error) {
217+
XCTAssertEqual(result, filePath);
218+
[pathExpectation fulfill];
219+
}];
220+
});
221+
[self waitForExpectationsWithTimeout:1 handler:nil];
222+
OCMVerifyAll(captureDeviceMock);
223+
}
172224
@end

packages/camera/camera_avfoundation/ios/Classes/FLTCam.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,9 +374,9 @@ - (void)captureToFileWithCompletion:(void (^)(NSString *_Nullable,
374374
extension = @"jpg";
375375
}
376376

377-
AVCaptureFlashMode avFlashMode = FCPGetAVCaptureFlashModeForPigeonFlashMode(_flashMode);
378-
if (avFlashMode != -1) {
379-
[settings setFlashMode:avFlashMode];
377+
// If the flash is in torch mode, no capture-level flash setting is needed.
378+
if (_flashMode != FCPPlatformFlashModeTorch) {
379+
[settings setFlashMode:FCPGetAVCaptureFlashModeForPigeonFlashMode(_flashMode)];
380380
}
381381
NSError *error;
382382
NSString *path = [self getTemporaryFilePathWithExtension:extension

packages/camera/camera_avfoundation/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: camera_avfoundation
22
description: iOS implementation of the camera plugin.
33
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
5-
version: 0.9.16+1
5+
version: 0.9.16+2
66

77
environment:
88
sdk: ^3.2.3

0 commit comments

Comments
 (0)