Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ public List<Long> filter(@NonNull Long identifier, @NonNull List<Long> cameraInf
}

List<CameraInfo> filteredCameraInfos = cameraSelector.filter(cameraInfosForFilter);
final CameraInfoFlutterApiImpl cameraInfoFlutterApiImpl =
new CameraInfoFlutterApiImpl(binaryMessenger, instanceManager);
List<Long> filteredCameraInfosIds = new ArrayList<Long>();

for (CameraInfo cameraInfo : filteredCameraInfos) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
import 'dart:async';

import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:flutter/foundation.dart';

import 'camera_info.dart';
import 'camera_selector.dart';
import 'process_camera_provider.dart';

/// The Android implementation of [CameraPlatform] that uses the CameraX library.
class AndroidCameraCameraX extends CameraPlatform {
Expand All @@ -13,9 +18,56 @@ class AndroidCameraCameraX extends CameraPlatform {
CameraPlatform.instance = AndroidCameraCameraX();
}

ProcessCameraProvider? _processCameraProvider;
@visibleForTesting
CameraSelector? backCameraSelector = CameraSelector.getDefaultBackCamera();
@visibleForTesting
CameraSelector? frontCameraSelector = CameraSelector.getDefaultFrontCamera();

/// Returns list of all available cameras and their descriptions.
@override
Future<List<CameraDescription>> availableCameras() async {
throw UnimplementedError('availableCameras() is not implemented.');
final List<CameraDescription> cameraDescriptions = <CameraDescription>[];

_processCameraProvider ??
setProcessCameraProvider(await ProcessCameraProvider.getInstance());
final List<CameraInfo> cameraInfos =
await _processCameraProvider!.getAvailableCameraInfos();

CameraLensDirection? cameraLensDirection;
int cameraCount = 0;
int? cameraSensorOrientation;
String? cameraName;

for (final CameraInfo cameraInfo in cameraInfos) {
// Determine the lens direction by filtering the CameraInfo
// TODO(gmackall): replace this with call to CameraInfo.getLensFacing when changes containing that method are available
Comment thread
gmackall marked this conversation as resolved.
if ((await backCameraSelector!.filter(<CameraInfo>[cameraInfo]))
.isNotEmpty) {
cameraLensDirection = CameraLensDirection.back;
} else if ((await frontCameraSelector!.filter(<CameraInfo>[cameraInfo]))
.isNotEmpty) {
cameraLensDirection = CameraLensDirection.front;
} else {
//Skip this CameraInfo as its lens direction is unknown
continue;
Comment thread
camsim99 marked this conversation as resolved.
}

cameraSensorOrientation = await cameraInfo.getSensorRotationDegrees();
cameraName = 'Camera $cameraCount';
Comment thread
camsim99 marked this conversation as resolved.
cameraCount++;

cameraDescriptions.add(CameraDescription(
name: cameraName,
lensDirection: cameraLensDirection,
sensorOrientation: cameraSensorOrientation));
}

return cameraDescriptions;
}

@visibleForTesting
void setProcessCameraProvider(ProcessCameraProvider processCameraProvider) {
this._processCameraProvider = processCameraProvider;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright 2013 The Flutter 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_android_camerax/camera_android_camerax.dart';
import 'package:camera_android_camerax/src/camera_info.dart';
import 'package:camera_android_camerax/src/camera_selector.dart';
import 'package:camera_android_camerax/src/process_camera_provider.dart';
import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';

import 'android_camera_camerax_test.mocks.dart';

@GenerateMocks(<Type>[
ProcessCameraProvider,
CameraSelector,
CameraInfo,
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();

test('Should fetch CameraDescription instances for available cameras',
() async {
// Arrange
final List<dynamic> returnData = <dynamic>[
<String, dynamic>{
'name': 'Camera 0',
'lensFacing': 'back',
'sensorOrientation': 0
},
<String, dynamic>{
'name': 'Camera 1',
'lensFacing': 'front',
'sensorOrientation': 90
}
];

//Create mocks to use
final MockProcessCameraProvider mockProcessCameraProvider =
MockProcessCameraProvider();
final MockCameraSelector mockBackCameraSelector = MockCameraSelector();
final MockCameraSelector mockFrontCameraSelector = MockCameraSelector();
final MockCameraInfo mockFrontCameraInfo = MockCameraInfo();
final MockCameraInfo mockBackCameraInfo = MockCameraInfo();
AndroidCameraCameraX.registerWith();

//Set class level ProcessCameraProvider and camera selectors to created mocks
final AndroidCameraCameraX androidCameraCamerax = AndroidCameraCameraX();
androidCameraCamerax.backCameraSelector = mockBackCameraSelector;
androidCameraCamerax.frontCameraSelector = mockFrontCameraSelector;
androidCameraCamerax.setProcessCameraProvider(mockProcessCameraProvider);

//Mock calls to native platform
when(mockProcessCameraProvider.getAvailableCameraInfos())
.thenAnswer((_) async => [mockBackCameraInfo, mockFrontCameraInfo]);
when(mockBackCameraSelector.filter([mockFrontCameraInfo]))
.thenAnswer((_) async => []);
when(mockBackCameraSelector.filter([mockBackCameraInfo]))
.thenAnswer((_) async => [mockBackCameraInfo]);
when(mockFrontCameraSelector.filter([mockBackCameraInfo]))
.thenAnswer((_) async => []);
when(mockFrontCameraSelector.filter([mockFrontCameraInfo]))
.thenAnswer((_) async => [mockFrontCameraInfo]);
when(mockBackCameraInfo.getSensorRotationDegrees())
.thenAnswer((_) async => 0);
when(mockFrontCameraInfo.getSensorRotationDegrees())
.thenAnswer((_) async => 90);

final List<CameraDescription> cameraDescriptions =
await androidCameraCamerax.availableCameras();

expect(cameraDescriptions.length, returnData.length);
for (int i = 0; i < returnData.length; i++) {
final Map<String, Object?> typedData =
(returnData[i] as Map<dynamic, dynamic>).cast<String, Object?>();
final CameraDescription cameraDescription = CameraDescription(
name: typedData['name']! as String,
lensDirection: (typedData['lensFacing']! as String) == 'front'
? CameraLensDirection.front
: CameraLensDirection.back,
sensorOrientation: typedData['sensorOrientation']! as int,
);
expect(cameraDescriptions[i], cameraDescription);
}
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Mocks generated by Mockito 5.3.2 from annotations
// in camera_android_camerax/test/android_camera_camerax_test.dart.
// Do not manually edit this file.

// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i3;

import 'package:camera_android_camerax/src/camera_info.dart' as _i4;
import 'package:camera_android_camerax/src/camera_selector.dart' as _i5;
import 'package:camera_android_camerax/src/process_camera_provider.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1;

// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class

/// A class which mocks [ProcessCameraProvider].
///
/// See the documentation for Mockito's code generation for more information.
class MockProcessCameraProvider extends _i1.Mock
implements _i2.ProcessCameraProvider {
MockProcessCameraProvider() {
_i1.throwOnMissingStub(this);
}

@override
_i3.Future<List<_i4.CameraInfo>> getAvailableCameraInfos() =>
(super.noSuchMethod(
Invocation.method(
#getAvailableCameraInfos,
[],
),
returnValue: _i3.Future<List<_i4.CameraInfo>>.value(<_i4.CameraInfo>[]),
) as _i3.Future<List<_i4.CameraInfo>>);
}

/// A class which mocks [CameraSelector].
///
/// See the documentation for Mockito's code generation for more information.
class MockCameraSelector extends _i1.Mock implements _i5.CameraSelector {
MockCameraSelector() {
_i1.throwOnMissingStub(this);
}

@override
_i3.Future<List<_i4.CameraInfo>> filter(List<_i4.CameraInfo>? cameraInfos) =>
(super.noSuchMethod(
Invocation.method(
#filter,
[cameraInfos],
),
returnValue: _i3.Future<List<_i4.CameraInfo>>.value(<_i4.CameraInfo>[]),
) as _i3.Future<List<_i4.CameraInfo>>);
}

/// A class which mocks [CameraInfo].
///
/// See the documentation for Mockito's code generation for more information.
class MockCameraInfo extends _i1.Mock implements _i4.CameraInfo {
MockCameraInfo() {
_i1.throwOnMissingStub(this);
}

@override
_i3.Future<int> getSensorRotationDegrees() => (super.noSuchMethod(
Invocation.method(
#getSensorRotationDegrees,
[],
),
returnValue: _i3.Future<int>.value(0),
) as _i3.Future<int>);
}