This repository was archived by the owner on Feb 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[camera] Dart side of camera API #1889
Merged
bparrishMines
merged 6 commits into
flutter:master
from
bparrishMines:support_android_dart
Jul 26, 2019
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
47d1d3c
Camera dart api for Android
bparrishMines 6ab10c1
documentation
bparrishMines cef20b5
Add liscensing and removed creation of a library
bparrishMines a27f7f3
removed duplicate import
bparrishMines 94d174e
Make code idiomatic
bparrishMines 93454bc
Merge branch 'master' of github.com:flutter/plugins into support_andr…
bparrishMines File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
packages/camera/lib/new/src/support_android/camera.dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| // 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 '../common/camera_channel.dart'; | ||
| import '../common/camera_mixins.dart'; | ||
| import '../common/native_texture.dart'; | ||
| import 'camera_info.dart'; | ||
|
|
||
| /// The Camera class used to set image capture settings, start/stop preview, snap pictures, and retrieve frames for encoding for video. | ||
| /// | ||
| /// This class is a client for the Camera service, which manages the actual | ||
| /// camera hardware. | ||
| /// | ||
| /// This exposes the deprecated Android | ||
| /// [Camera](https://developer.android.com/reference/android/hardware/Camera) | ||
| /// API. This should only be used with Android sdk versions less than 21. | ||
| class Camera with NativeMethodCallHandler { | ||
| Camera._(); | ||
|
|
||
| bool _isClosed = false; | ||
|
|
||
| /// Retrieves the number of physical cameras available on this device. | ||
| static Future<int> getNumberOfCameras() { | ||
| return CameraChannel.channel.invokeMethod<int>( | ||
| 'Camera#getNumberOfCameras', | ||
| ); | ||
| } | ||
|
|
||
| /// Creates a new [Camera] object to access a particular hardware camera. | ||
| /// | ||
| /// If the same camera is opened by other applications, this will throw a | ||
| /// [PlatformException]. | ||
| /// | ||
| /// You must call [release] when you are done using the camera, otherwise it | ||
| /// will remain locked and be unavailable to other applications. | ||
| /// | ||
| /// Your application should only have one [Camera] object active at a time for | ||
| /// a particular hardware camera. | ||
| static Camera open(int cameraId) { | ||
| final Camera camera = Camera._(); | ||
|
|
||
| CameraChannel.channel.invokeMethod<int>( | ||
| 'Camera#open', | ||
| <String, dynamic>{'cameraId': cameraId, 'cameraHandle': camera.handle}, | ||
| ); | ||
|
|
||
| return camera; | ||
| } | ||
|
|
||
| /// Retrieves information about a particular camera. | ||
| /// | ||
| /// If [getNumberOfCameras] returns N, the valid id is 0 to N-1. | ||
| static Future<CameraInfo> getCameraInfo(int cameraId) async { | ||
| final Map<String, dynamic> infoMap = | ||
| await CameraChannel.channel.invokeMapMethod<String, dynamic>( | ||
| 'Camera#getCameraInfo', | ||
| <String, dynamic>{'cameraId': cameraId}, | ||
| ); | ||
|
|
||
| return CameraInfo.fromMap(infoMap); | ||
| } | ||
|
|
||
| /// Sets the [NativeTexture] to be used for live preview. | ||
| /// | ||
| /// This method must be called before [startPreview]. | ||
| /// | ||
| /// The one exception is that if the preview native texture is not set (or | ||
| /// set to null) before [startPreview] is called, then this method may be | ||
| /// called once with a non-null parameter to set the preview texture. | ||
| /// (This allows camera setup and surface creation to happen in parallel, | ||
| /// saving time.) The preview native texture may not otherwise change while | ||
| /// preview is running. | ||
| set previewTexture(NativeTexture texture) { | ||
| assert(!_isClosed); | ||
|
|
||
| CameraChannel.channel.invokeMethod<void>( | ||
| 'Camera#previewTexture', | ||
| <String, dynamic>{'handle': handle, 'nativeTexture': texture?.asMap()}, | ||
| ); | ||
| } | ||
|
|
||
| /// Starts capturing and drawing preview frames to the screen. | ||
| /// | ||
| /// Preview will not actually start until a surface is supplied with | ||
| /// [previewTexture]. | ||
| Future<void> startPreview() { | ||
| assert(!_isClosed); | ||
|
|
||
| return CameraChannel.channel.invokeMethod<void>( | ||
| 'Camera#startPreview', | ||
| <String, dynamic>{'handle': handle}, | ||
| ); | ||
| } | ||
|
|
||
| /// Stops capturing and drawing preview frames to the [previewTexture], and resets the camera for a future call to [startPreview]. | ||
| Future<void> stopPreview() { | ||
| assert(!_isClosed); | ||
|
|
||
| return CameraChannel.channel.invokeMethod<void>( | ||
| 'Camera#stopPreview', | ||
| <String, dynamic>{'handle': handle}, | ||
| ); | ||
| } | ||
|
|
||
| /// Disconnects and releases the Camera object resources. | ||
| /// | ||
| /// You must call this as soon as you're done with the Camera object. | ||
| Future<void> release() { | ||
| if (_isClosed) return Future<void>.value(); | ||
|
|
||
| _isClosed = true; | ||
| return CameraChannel.channel.invokeMethod<void>( | ||
| 'Camera#release', | ||
| <String, dynamic>{'handle': handle}, | ||
| ); | ||
| } | ||
| } | ||
68 changes: 68 additions & 0 deletions
68
packages/camera/lib/new/src/support_android/camera_info.dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| // 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 'package:flutter/foundation.dart'; | ||
|
|
||
| import '../common/camera_interface.dart'; | ||
|
|
||
| /// The direction that the camera faces. | ||
| enum Facing { back, front } | ||
|
|
||
| /// Information about a camera. | ||
| /// | ||
| /// Retrieved from [Camera.getCameraInfo]. | ||
| class CameraInfo implements CameraDescription { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| const CameraInfo({ | ||
| @required this.id, | ||
| @required this.facing, | ||
| @required this.orientation, | ||
| }) : assert(id != null), | ||
| assert(facing != null), | ||
| assert(orientation != null); | ||
|
|
||
| factory CameraInfo.fromMap(Map<String, dynamic> map) { | ||
| return CameraInfo( | ||
| id: map['id'], | ||
| orientation: map['orientation'], | ||
| facing: Facing.values.firstWhere( | ||
| (Facing facing) => facing.toString() == map['facing'], | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| /// Identifier for a particular camera. | ||
| final int id; | ||
|
|
||
| /// The direction that the camera faces. | ||
| final Facing facing; | ||
|
|
||
| /// The orientation of the camera image. | ||
| /// | ||
| /// The value is the angle that the camera image needs to be rotated clockwise | ||
| /// so it shows correctly on the display in its natural orientation. | ||
| /// It should be 0, 90, 180, or 270. | ||
| /// | ||
| /// For example, suppose a device has a naturally tall screen. The back-facing | ||
| /// camera sensor is mounted in landscape. You are looking at the screen. If | ||
| /// the top side of the camera sensor is aligned with the right edge of the | ||
| /// screen in natural orientation, the value should be 90. If the top side of | ||
| /// a front-facing camera sensor is aligned with the right of the screen, the | ||
| /// value should be 270. | ||
| final int orientation; | ||
|
|
||
| @override | ||
| String get name => id.toString(); | ||
|
|
||
| @override | ||
| LensDirection get direction { | ||
| switch (facing) { | ||
| case Facing.front: | ||
| return LensDirection.front; | ||
| case Facing.back: | ||
| return LensDirection.back; | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
| } | ||
141 changes: 141 additions & 0 deletions
141
packages/camera/test/support_android/support_android_test.dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| // 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 'package:camera/new/src/support_android/camera_info.dart'; | ||
| import 'package:camera/new/src/support_android/camera.dart'; | ||
| import 'package:flutter/services.dart'; | ||
| import 'package:flutter_test/flutter_test.dart'; | ||
| import 'package:camera/new/src/camera_testing.dart'; | ||
|
|
||
| void main() { | ||
| group('Support Android Camera', () { | ||
| group('$Camera', () { | ||
| final List<MethodCall> log = <MethodCall>[]; | ||
| setUpAll(() { | ||
| CameraTesting.channel | ||
| .setMockMethodCallHandler((MethodCall methodCall) async { | ||
| log.add(methodCall); | ||
| switch (methodCall.method) { | ||
| case 'Camera#getNumberOfCameras': | ||
| return 3; | ||
| case 'Camera#open': | ||
| return null; | ||
| case 'Camera#getCameraInfo': | ||
| return <dynamic, dynamic>{ | ||
| 'id': 3, | ||
| 'orientation': 90, | ||
| 'facing': Facing.front.toString(), | ||
| }; | ||
| case 'Camera#startPreview': | ||
| return null; | ||
| case 'Camera#stopPreview': | ||
| return null; | ||
| case 'Camera#release': | ||
| return null; | ||
| } | ||
|
|
||
| throw ArgumentError.value( | ||
| methodCall.method, | ||
| 'methodCall.method', | ||
| 'No method found for', | ||
| ); | ||
| }); | ||
| }); | ||
|
|
||
| setUp(() { | ||
| log.clear(); | ||
| CameraTesting.nextHandle = 0; | ||
| }); | ||
|
|
||
| test('getNumberOfCameras', () async { | ||
| final int result = await Camera.getNumberOfCameras(); | ||
|
|
||
| expect(result, 3); | ||
| expect(log, <Matcher>[ | ||
| isMethodCall( | ||
| '$Camera#getNumberOfCameras', | ||
| arguments: null, | ||
| ) | ||
| ]); | ||
| }); | ||
|
|
||
| test('open', () { | ||
| Camera.open(14); | ||
|
|
||
| expect(log, <Matcher>[ | ||
| isMethodCall( | ||
| '$Camera#open', | ||
| arguments: <String, dynamic>{ | ||
| 'cameraId': 14, | ||
| 'cameraHandle': 0, | ||
| }, | ||
| ) | ||
| ]); | ||
| }); | ||
|
|
||
| test('getCameraInfo', () async { | ||
| final CameraInfo info = await Camera.getCameraInfo(14); | ||
|
|
||
| expect(info.id, 3); | ||
| expect(info.orientation, 90); | ||
| expect(info.facing, Facing.front); | ||
|
|
||
| expect(log, <Matcher>[ | ||
| isMethodCall( | ||
| '$Camera#getCameraInfo', | ||
| arguments: <String, dynamic>{'cameraId': 14}, | ||
| ) | ||
| ]); | ||
| }); | ||
|
|
||
| test('startPreview', () { | ||
| final Camera camera = Camera.open(0); | ||
|
|
||
| log.clear(); | ||
| camera.startPreview(); | ||
|
|
||
| expect(log, <Matcher>[ | ||
| isMethodCall( | ||
| '$Camera#startPreview', | ||
| arguments: <String, dynamic>{ | ||
| 'handle': 0, | ||
| }, | ||
| ) | ||
| ]); | ||
| }); | ||
|
|
||
| test('stopPreview', () { | ||
| final Camera camera = Camera.open(0); | ||
|
|
||
| log.clear(); | ||
| camera.stopPreview(); | ||
|
|
||
| expect(log, <Matcher>[ | ||
| isMethodCall( | ||
| '$Camera#stopPreview', | ||
| arguments: <String, dynamic>{ | ||
| 'handle': 0, | ||
| }, | ||
| ) | ||
| ]); | ||
| }); | ||
|
|
||
| test('release', () { | ||
| final Camera camera = Camera.open(0); | ||
|
|
||
| log.clear(); | ||
| camera.release(); | ||
|
|
||
| expect(log, <Matcher>[ | ||
| isMethodCall( | ||
| '$Camera#release', | ||
| arguments: <String, dynamic>{ | ||
| 'handle': 0, | ||
| }, | ||
| ) | ||
| ]); | ||
| }); | ||
| }); | ||
| }); | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://developer.android.com/reference/android/hardware/Camera