diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 0fcda278d836..468ca80b7830 100644 --- a/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -60,6 +60,7 @@ public class Camera { private boolean recordingVideo; private CamcorderProfile recordingProfile; private int currentOrientation = ORIENTATION_UNKNOWN; + private boolean isTorchOn = false; // Mirrors camera.dart public enum ResolutionPreset { @@ -278,8 +279,7 @@ public void onCaptureFailed( } } - private void createCaptureSession(int templateType, Surface... surfaces) - throws CameraAccessException { + private void createCaptureSession(int templateType, Surface... surfaces) throws CameraAccessException { createCaptureSession(templateType, null, surfaces); } @@ -318,8 +318,10 @@ public void onConfigured(@NonNull CameraCaptureSession session) { return; } cameraCaptureSession = session; - captureRequestBuilder.set( - CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); + captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); + if(isTorchOn){ + captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); + } cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null); if (onSuccessCallback != null) { onSuccessCallback.run(); @@ -421,11 +423,13 @@ public void resumeVideoRecording(@NonNull final Result result) { } public void startPreview() throws CameraAccessException { + isTorchOn = false; createCaptureSession(CameraDevice.TEMPLATE_PREVIEW, pictureImageReader.getSurface()); } - public void startPreviewWithImageStream(EventChannel imageStreamChannel) + public void startPreviewWithImageStream(EventChannel imageStreamChannel, boolean useTorch) throws CameraAccessException { + isTorchOn = useTorch; createCaptureSession(CameraDevice.TEMPLATE_RECORD, imageStreamReader.getSurface()); imageStreamChannel.setStreamHandler( diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index cb58d19a9a02..02cae9dbb173 100644 --- a/packages/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -106,7 +106,17 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) case "startImageStream": { try { - camera.startPreviewWithImageStream(imageStreamChannel); + camera.startPreviewWithImageStream(imageStreamChannel, false); + result.success(null); + } catch (Exception e) { + handleException(e, result); + } + break; + } + case "startImageStreamWithTorch": + { + try { + camera.startPreviewWithImageStream(imageStreamChannel, true); result.success(null); } catch (Exception e) { handleException(e, result); diff --git a/packages/camera/example/lib/main.dart b/packages/camera/example/lib/main.dart index ce8d37457123..c52b894785a9 100644 --- a/packages/camera/example/lib/main.dart +++ b/packages/camera/example/lib/main.dart @@ -110,6 +110,10 @@ class _CameraExampleHomeState extends State children: [ _cameraTogglesRowWidget(), _thumbnailWidget(), + FlatButton( + onPressed: () => controller.startImageStreamWithTorch((image) => print(imagePath)), + child: Text('Stream with Torch'), + ) ], ), ), diff --git a/packages/camera/lib/camera.dart b/packages/camera/lib/camera.dart index ce9fd9430dde..3a5cd74c5ce8 100644 --- a/packages/camera/lib/camera.dart +++ b/packages/camera/lib/camera.dart @@ -414,6 +414,55 @@ class CameraController extends ValueNotifier { ); } + /// Start streaming images from platform camera with torch on. + /// + /// Settings for capturing images on iOS and Android is set to always use the + /// latest image available from the camera and will drop all other images. + /// + /// When running continuously with [CameraPreview] widget, this function runs + /// best with [ResolutionPreset.low]. Running on [ResolutionPreset.high] can + /// have significant frame rate drops for [CameraPreview] on lower end + /// devices. + /// + /// Throws a [CameraException] if image streaming or video recording has + /// already started. + // TODO(bmparr): Add settings for resolution and fps. + Future startImageStreamWithTorch(onLatestImageAvailable onAvailable) async { + if (!value.isInitialized || _isDisposed) { + throw CameraException( + 'Uninitialized CameraController', + 'startImageStream was called on uninitialized CameraController.', + ); + } + if (value.isRecordingVideo) { + throw CameraException( + 'A video recording is already started.', + 'startImageStream was called while a video is being recorded.', + ); + } + if (value.isStreamingImages) { + throw CameraException( + 'A camera has started streaming images.', + 'startImageStream was called while a camera was streaming images.', + ); + } + + try { + await _channel.invokeMethod('startImageStreamWithTorch'); + value = value.copyWith(isStreamingImages: true); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + const EventChannel cameraEventChannel = + EventChannel('plugins.flutter.io/camera/imageStream'); + _imageStreamSubscription = + cameraEventChannel.receiveBroadcastStream().listen( + (dynamic imageData) { + onAvailable(CameraImage._fromPlatformData(imageData)); + }, + ); + } + /// Stop streaming images from platform camera. /// /// Throws a [CameraException] if image streaming was not started or video