From d5fe2a9a42519eb4ed831a912e57674693e2dd96 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 21 Dec 2020 09:51:36 +0100 Subject: [PATCH 1/2] Added torch mode functionality for Android and iOS. --- packages/camera/camera/CHANGELOG.md | 4 + .../io/flutter/plugins/camera/Camera.java | 8 +- .../plugins/camera/types/FlashMode.java | 3 +- .../plugins/camera/types/FlashModeTest.java | 4 + packages/camera/camera/example/lib/main.dart | 9 ++ .../camera/camera/ios/Classes/CameraPlugin.m | 117 +++++++++++++----- packages/camera/camera/pubspec.yaml | 2 +- .../method_channel_camera_test.dart | 3 + 8 files changed, 117 insertions(+), 33 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 168ed5557123..fe4d1bbaa983 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.3 + +* Adds torch mode as a flash mode for Android and iOS implementations. + ## 0.6.2 * Add zoom support for Android and iOS implementations. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 3e8bbc7b295b..cae666d6742a 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -532,7 +532,6 @@ public void setFlashMode(@NonNull final Result result, FlashMode mode) return; } // Get flash - this.flashMode = mode; initPreviewCaptureBuilder(); this.cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); @@ -553,11 +552,16 @@ private void initPreviewCaptureBuilder() { captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; case always: - default: captureRequestBuilder.set( CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); break; + case torch: + default: + captureRequestBuilder.set( + CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); + captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); + break; } } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java index eddeddc47eab..99d4915b3a6a 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/FlashMode.java @@ -4,7 +4,8 @@ public enum FlashMode { off, auto, - always; + always, + torch; public static FlashMode getValueForString(String modeStr) { try { diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java index 0549e4fc750e..d2674e8c7e06 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java @@ -16,6 +16,10 @@ public void getValueForString_returns_correct_values() { "Returns FlashMode.always for 'always'", FlashMode.getValueForString("always"), FlashMode.always); + assertEquals( + "Returns FlashMode.torch for 'torch'", + FlashMode.getValueForString("torch"), + FlashMode.torch); } @Test diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 049141d3935e..ee8e2c259b3d 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -256,6 +256,15 @@ class _CameraExampleHomeState extends State ? () => onFlashModeButtonPressed(FlashMode.always) : null, ), + IconButton( + icon: const Icon(Icons.highlight), + color: controller?.value?.flashMode == FlashMode.torch + ? Colors.orange + : Colors.blue, + onPressed: controller != null + ? () => onFlashModeButtonPressed(FlashMode.torch) + : null, + ), ], ); } diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index c13ff60abd0a..f71b364cd0d6 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -134,13 +134,23 @@ - (UIImageOrientation)getImageRotation { } @end -static AVCaptureFlashMode getFlashModeForString(NSString *mode) { +// Mirrors FlashMode in flash_mode.dart +typedef enum { + FlashModeOff, + FlashModeAuto, + FlashModeAlways, + FlashModeTorch, +} FlashMode; + +static FlashMode getFlashModeForString(NSString *mode) { if ([mode isEqualToString:@"off"]) { - return AVCaptureFlashModeOff; + return FlashModeOff; } else if ([mode isEqualToString:@"auto"]) { - return AVCaptureFlashModeAuto; + return FlashModeAuto; } else if ([mode isEqualToString:@"always"]) { - return AVCaptureFlashModeOn; + return FlashModeAlways; + } else if ([mode isEqualToString:@"torch"]) { + return FlashModeTorch; } else { NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSURLErrorUnknown @@ -152,6 +162,20 @@ static AVCaptureFlashMode getFlashModeForString(NSString *mode) { } } +static AVCaptureFlashMode getAVCaptureFlashModeForFlashMode(FlashMode mode) { + switch (mode) { + case FlashModeOff: + return AVCaptureFlashModeOff; + case FlashModeAuto: + return AVCaptureFlashModeAuto; + case FlashModeAlways: + return AVCaptureFlashModeOn; + case FlashModeTorch: + default: + return -1; + } +} + // Mirrors ResolutionPreset in camera.dart typedef enum { veryLow, @@ -219,7 +243,7 @@ @interface FLTCam : NSObject *)messenger { @@ -854,6 +907,12 @@ - (BOOL)setupWriterForPath:(NSString *)path { [_audioOutput setSampleBufferDelegate:self queue:_dispatchQueue]; } + if (_flashMode == FlashModeTorch) { + [self.captureDevice lockForConfiguration:nil]; + [self.captureDevice setTorchMode:AVCaptureTorchModeOn]; + [self.captureDevice unlockForConfiguration]; + } + [_videoWriter addInput:_videoWriterInput]; [_captureVideoOutput setSampleBufferDelegate:self queue:_dispatchQueue]; diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index d823dd383281..1bccbd4d45df 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -2,7 +2,7 @@ name: camera description: A Flutter plugin for getting information about and controlling the camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. -version: 0.6.2 +version: 0.6.3 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera dependencies: diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index c461b1fd583c..82b01015e4f4 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -478,12 +478,15 @@ void main() { ); // Act + await camera.setFlashMode(cameraId, FlashMode.torch); await camera.setFlashMode(cameraId, FlashMode.always); await camera.setFlashMode(cameraId, FlashMode.auto); await camera.setFlashMode(cameraId, FlashMode.off); // Assert expect(channel.log, [ + isMethodCall('setFlashMode', + arguments: {'cameraId': cameraId, 'mode': 'torch'}), isMethodCall('setFlashMode', arguments: {'cameraId': cameraId, 'mode': 'always'}), isMethodCall('setFlashMode', From 47cd2764e9eb27354eea423d9557c4b8eaf79f21 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Mon, 21 Dec 2020 11:56:34 +0100 Subject: [PATCH 2/2] Format objective c code --- .../camera/camera/ios/Classes/CameraPlugin.m | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/packages/camera/camera/ios/Classes/CameraPlugin.m b/packages/camera/camera/ios/Classes/CameraPlugin.m index f71b364cd0d6..d54695233bdb 100644 --- a/packages/camera/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera/ios/Classes/CameraPlugin.m @@ -722,53 +722,53 @@ - (void)resumeVideoRecordingWithResult:(FlutterResult)result { - (void)setFlashModeWithResult:(FlutterResult)result mode:(NSString *)modeStr { FlashMode mode; - @try { - mode = getFlashModeForString(modeStr); - } @catch (NSError *e) { - result(getFlutterError(e)); + @try { + mode = getFlashModeForString(modeStr); + } @catch (NSError *e) { + result(getFlutterError(e)); + return; + } + if (mode == FlashModeTorch) { + if (!_captureDevice.hasTorch) { + result([FlutterError errorWithCode:@"setFlashModeFailed" + message:@"Device does not support torch mode" + details:nil]); return; } - if (mode == FlashModeTorch) { - if (!_captureDevice.hasTorch) { - result([FlutterError errorWithCode:@"setFlashModeFailed" - message:@"Device does not support torch mode" - details:nil]); - return; - } - if (!_captureDevice.isTorchAvailable) { - result([FlutterError errorWithCode:@"setFlashModeFailed" - message:@"Torch mode is currently not available" - details:nil]); - return; - } - if (_captureDevice.torchMode != AVCaptureTorchModeOn) { - [_captureDevice lockForConfiguration:nil]; - [_captureDevice setTorchMode:AVCaptureTorchModeOn]; - [_captureDevice unlockForConfiguration]; - } - } else { - if (!_captureDevice.hasFlash) { - result([FlutterError errorWithCode:@"setFlashModeFailed" - message:@"Device does not have flash capabilities" - details:nil]); - return; - } - AVCaptureFlashMode avFlashMode = getAVCaptureFlashModeForFlashMode(mode); - if (![_capturePhotoOutput.supportedFlashModes - containsObject:[NSNumber numberWithInt:((int)avFlashMode)]]) { - result([FlutterError errorWithCode:@"setFlashModeFailed" - message:@"Device does not support this specific flash mode" - details:nil]); - return; - } - if (_captureDevice.torchMode != AVCaptureTorchModeOff) { - [_captureDevice lockForConfiguration:nil]; - [_captureDevice setTorchMode:AVCaptureTorchModeOff]; - [_captureDevice unlockForConfiguration]; - } + if (!_captureDevice.isTorchAvailable) { + result([FlutterError errorWithCode:@"setFlashModeFailed" + message:@"Torch mode is currently not available" + details:nil]); + return; } - _flashMode = mode; - result(nil); + if (_captureDevice.torchMode != AVCaptureTorchModeOn) { + [_captureDevice lockForConfiguration:nil]; + [_captureDevice setTorchMode:AVCaptureTorchModeOn]; + [_captureDevice unlockForConfiguration]; + } + } else { + if (!_captureDevice.hasFlash) { + result([FlutterError errorWithCode:@"setFlashModeFailed" + message:@"Device does not have flash capabilities" + details:nil]); + return; + } + AVCaptureFlashMode avFlashMode = getAVCaptureFlashModeForFlashMode(mode); + if (![_capturePhotoOutput.supportedFlashModes + containsObject:[NSNumber numberWithInt:((int)avFlashMode)]]) { + result([FlutterError errorWithCode:@"setFlashModeFailed" + message:@"Device does not support this specific flash mode" + details:nil]); + return; + } + if (_captureDevice.torchMode != AVCaptureTorchModeOff) { + [_captureDevice lockForConfiguration:nil]; + [_captureDevice setTorchMode:AVCaptureTorchModeOff]; + [_captureDevice unlockForConfiguration]; + } + } + _flashMode = mode; + result(nil); } - (void)startImageStreamWithMessenger:(NSObject *)messenger {