| // Copyright 2019 The Chromium 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:async'; |
| |
| import 'package:flutter/foundation.dart'; |
| |
| import 'common/camera_interface.dart'; |
| |
| /// Controls a device camera. |
| /// |
| /// Use [CameraController.availableCameras] to get a list of available cameras. |
| /// |
| /// This class is used as a simple interface to control a camera on Android or |
| /// iOS. |
| /// |
| /// Only one instance of [CameraController] can be active at a time. If you call |
| /// [initialize] on a [CameraController] while another is active, the old |
| /// controller will be disposed before initializing the new controller. |
| /// |
| /// Example using [CameraController]: |
| /// |
| /// ```dart |
| /// final List<CameraDescription> cameras = async CameraController.availableCameras(); |
| /// final CameraController controller = CameraController(description: cameras[0]); |
| /// controller.initialize(); |
| /// controller.start(); |
| /// ``` |
| class CameraController { |
| /// Default constructor. |
| /// |
| /// Use [CameraController.availableCameras] to get a list of available |
| /// cameras. |
| /// |
| /// This will choose the best [CameraConfigurator] for the current device. |
| factory CameraController({@required CameraDescription description}) { |
| return CameraController._( |
| description: description, |
| configurator: _createDefaultConfigurator(description), |
| api: _getCameraApi(description), |
| ); |
| } |
| |
| CameraController._({ |
| @required this.description, |
| @required this.configurator, |
| @required this.api, |
| }) : assert(description != null), |
| assert(configurator != null), |
| assert(api != null); |
| |
| /// Constructor for defining your own [CameraConfigurator]. |
| /// |
| /// Use [CameraController.availableCameras] to get a list of available |
| /// cameras. |
| factory CameraController.customConfigurator({ |
| @required CameraDescription description, |
| @required CameraConfigurator configurator, |
| }) { |
| return CameraController._( |
| description: description, |
| configurator: configurator, |
| api: _getCameraApi(description), |
| ); |
| } |
| |
| static const String _isNotInitializedMessage = 'Initialize was not called.'; |
| static const String _isDisposedMessage = 'This controller has been disposed.'; |
| |
| // Keep only one active instance of CameraController. |
| static CameraController _instance; |
| |
| bool _isDisposed = false; |
| |
| /// Details for the camera this controller accesses. |
| final CameraDescription description; |
| |
| /// Configurator used to control the camera. |
| final CameraConfigurator configurator; |
| |
| /// Api used by the [configurator]. |
| final CameraApi api; |
| |
| bool get isDisposed => _isDisposed; |
| |
| /// Retrieves a list of available cameras for the current device. |
| /// |
| /// This will choose the best [CameraAPI] for the current device. |
| static Future<List<CameraDescription>> availableCameras() async { |
| throw UnimplementedError('$defaultTargetPlatform not supported'); |
| } |
| |
| /// Initializes the camera on the device. |
| /// |
| /// You must call [dispose] when you are done using the camera, otherwise it |
| /// will remain locked and be unavailable to other applications. |
| /// |
| /// Only one instance of [CameraController] can be active at a time. If you |
| /// call [initialize] on a [CameraController] while another is active, the old |
| /// controller will be disposed before initializing the new controller. |
| Future<void> initialize() { |
| if (_instance == this) { |
| return Future<void>.value(); |
| } |
| |
| final Completer<void> completer = Completer<void>(); |
| |
| if (_instance != null) { |
| _instance |
| .dispose() |
| .then((_) => configurator.initialize()) |
| .then((_) => completer.complete()); |
| } |
| _instance = this; |
| |
| return completer.future; |
| } |
| |
| /// Begins the flow of data between the inputs and outputs connected to the camera instance. |
| Future<void> start() { |
| assert(!_isDisposed, _isDisposedMessage); |
| assert(_instance != this, _isNotInitializedMessage); |
| |
| return configurator.start(); |
| } |
| |
| /// Stops the flow of data between the inputs and outputs connected to the camera instance. |
| Future<void> stop() { |
| assert(!_isDisposed, _isDisposedMessage); |
| assert(_instance != this, _isNotInitializedMessage); |
| |
| return configurator.stop(); |
| } |
| |
| /// Deallocate all resources and disables further use of the controller. |
| Future<void> dispose() { |
| _instance = null; |
| _isDisposed = true; |
| return configurator.dispose(); |
| } |
| |
| static CameraConfigurator _createDefaultConfigurator( |
| CameraDescription description, |
| ) { |
| final CameraApi api = _getCameraApi(description); |
| switch (api) { |
| case CameraApi.android: |
| throw UnimplementedError(); |
| case CameraApi.iOS: |
| throw UnimplementedError(); |
| case CameraApi.supportAndroid: |
| throw UnimplementedError(); |
| } |
| |
| return null; // Unreachable code |
| } |
| |
| static CameraApi _getCameraApi(CameraDescription description) { |
| return CameraApi.iOS; |
| |
| // TODO(bparrishMines): Uncomment this when platform specific code is added. |
| /* |
| throw ArgumentError.value( |
| description.runtimeType, |
| 'description.runtimeType', |
| 'Failed to get $CameraApi from', |
| ); |
| */ |
| } |
| } |