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 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7894cc2
Add base code from proof of concept
camsim99 Feb 7, 2023
efca3ed
Fix analyzer
camsim99 Feb 7, 2023
b4ae1db
Add example app and tests
camsim99 Feb 9, 2023
7c8168b
Actually add tets and visible for testing annotation
camsim99 Feb 9, 2023
93d442b
Make methods private
camsim99 Feb 9, 2023
d99ef9c
Merge remote-tracking branch 'upstream/main' into camx_preview
camsim99 Feb 9, 2023
bf1ca9a
Fix tests
camsim99 Feb 9, 2023
b237d6e
Fix analyze:
camsim99 Feb 10, 2023
a21429a
Update changelog
camsim99 Feb 10, 2023
dcff8bc
Formatting
camsim99 Feb 10, 2023
a183944
Merge remote-tracking branch 'upstream/main' into camx_preview
camsim99 Feb 10, 2023
f163907
Update todos with links and modify camera controller
camsim99 Feb 10, 2023
285659d
Format and add availableCameras
camsim99 Feb 10, 2023
cffc0ac
Fix mocks
camsim99 Feb 10, 2023
889802d
Try bumping mockito version
camsim99 Feb 10, 2023
24ee512
Review documentation
camsim99 Feb 10, 2023
573cf33
Re-generate mocks
camsim99 Feb 13, 2023
d08c087
Fix typo
camsim99 Feb 14, 2023
1e1dd8b
Fix another typo
camsim99 Feb 14, 2023
e1cea85
Address review and fix bug
camsim99 Feb 14, 2023
5ccc872
Merge remote-tracking branch 'upstream/main' into camx_preview
camsim99 Feb 14, 2023
7129845
Fix analyze
camsim99 Feb 14, 2023
c54c547
Merge remote-tracking branch 'upstream/main' into camx_preview
camsim99 Feb 14, 2023
5f30bc7
Fix tests
camsim99 Feb 14, 2023
8fc71f9
Foramtting
camsim99 Feb 14, 2023
d50bd87
Clear preview is paused
camsim99 Feb 15, 2023
de2fc29
Add unknown lens
camsim99 Feb 15, 2023
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
Prev Previous commit
Next Next commit
Merge remote-tracking branch 'upstream/main' into camx_preview
  • Loading branch information
camsim99 committed Feb 9, 2023
commit d99ef9ce80a30530bf2e68b22e03d65db9b02692
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:flutter/widgets.dart';
import 'package:stream_transform/stream_transform.dart';

import 'camera.dart';
import 'camera_info.dart';
import 'camera_selector.dart';
import 'camerax_library.g.dart';
import 'preview.dart';
Expand All @@ -27,10 +28,12 @@ class AndroidCameraCameraX extends CameraPlatform {
// Objects used to access camera functionality:

/// The [ProcessCameraProvider] instance used to access camera functionality.
@visibleForTesting
ProcessCameraProvider? processCameraProvider;

/// The [Camera] instance returned by the [processCameraProvider] when a [UseCase] is
/// bound to the lifecycle of the camera it manages.
@visibleForTesting
Camera? camera;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: It may be worth moving all the @visibleForTesting fields and methods to a separate class and pass that class as an optional parameter in a constructor. Calling it something like AndroidCameraXProxy. This could help organize the code a bit. You can decide which is easier to use.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would honestly find this kind of confusing, especially since this would involve some of the major use case instances. Are you open to reconsidering this later on? I could see it helping organizationally if there ends up being a lot of different fields (especially booleans and things that aren't necessarily CameraX objects) that need to be visible or there are a bunch more methods we'll need to create to mock.


// Use cases to configure and bind to ProcessCameraProvider instance:
Expand Down Expand Up @@ -67,7 +70,7 @@ class AndroidCameraCameraX extends CameraPlatform {
Future<List<CameraDescription>> availableCameras() async {
final List<CameraDescription> cameraDescriptions = <CameraDescription>[];

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

Expand All @@ -79,10 +82,10 @@ class AndroidCameraCameraX extends CameraPlatform {
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
if ((await backCameraSelector!.filter(<CameraInfo>[cameraInfo]))
if ((await createCameraSelector(CameraSelector.LENS_FACING_BACK).filter(<CameraInfo>[cameraInfo]))
.isNotEmpty) {
cameraLensDirection = CameraLensDirection.back;
} else if ((await frontCameraSelector!.filter(<CameraInfo>[cameraInfo]))
} else if ((await createCameraSelector(CameraSelector.LENS_FACING_FRONT).filter(<CameraInfo>[cameraInfo]))
.isNotEmpty) {
cameraLensDirection = CameraLensDirection.front;
} else {
Expand Down Expand Up @@ -349,7 +352,14 @@ class AndroidCameraCameraX extends CameraPlatform {

@visibleForTesting
CameraSelector createCameraSelector(int cameraSelectorLensDirection) {
return CameraSelector(lensFacing: cameraSelectorLensDirection);
switch(cameraSelectorLensDirection) {
case CameraSelector.LENS_FACING_FRONT:
return CameraSelector.getDefaultFrontCamera();
case CameraSelector.LENS_FACING_BACK:
return CameraSelector.getDefaultBackCamera();
default:
return CameraSelector(lensFacing: cameraSelectorLensDirection);
}
}

@visibleForTesting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:async/async.dart';
import 'package:camera_android_camerax/camera_android_camerax.dart';
import 'package:camera_android_camerax/src/camerax_library.g.dart';
import 'package:camera_android_camerax/src/camera.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/preview.dart';
import 'package:camera_android_camerax/src/process_camera_provider.dart';
Expand All @@ -24,15 +25,71 @@ import 'android_camera_camerax_test.mocks.dart';
@GenerateNiceMocks(<MockSpec<Object>>[
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stuartmorgan @bparrishMines Generate mocks for BuildContext this way has caused me to run into this error: https://cirrus-ci.com/task/6299387630977024?logs=unit_test#L203. This passes for me locally, so I'm wondering if y'all have any insight as to what might be happening with the CI?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the error is about a typedef that was added on master recently, so it's not on stable. You can probably just generate the mocks on stable.

MockSpec<BuildContext>(),
MockSpec<Camera>(),
MockSpec<CameraInfo>(),
MockSpec<CameraSelector>(),
MockSpec<Preview>(),
MockSpec<ProcessCameraProvider>(),
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();

test('Should fetch CameraDescription instances for available cameras',
() async {
// Arrange
final MockAndroidCameraCamerax camera = MockAndroidCameraCamerax();
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 MockCameraInfo mockFrontCameraInfo = MockCameraInfo();
final MockCameraInfo mockBackCameraInfo = MockCameraInfo();

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

final List<CameraDescription> cameraDescriptions =
await camera.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);
}
});

test(
'createCamera requests permissions, starts listening for device orientation changes, and returns flutter surface texture ID ',
'createCamera requests permissions, starts listening for device orientation changes, and returns flutter surface texture ID',
() async {
final MockAndroidCameraCamerax camera = MockAndroidCameraCamerax();
const CameraLensDirection testLensDirection = CameraLensDirection.back;
Expand All @@ -58,7 +115,7 @@ void main() {
expect(camera.startedListeningForDeviceOrientationChanges, isTrue);

// Verify CameraSelector is set with appropriate lens direction.
expect(camera.cameraSelector, equals(camera.testCameraSelector));
expect(camera.cameraSelector, equals(camera.mockBackCameraSelector));

// Verify ProcessCameraProvider instance is received.
expect(
Expand Down Expand Up @@ -306,6 +363,8 @@ class MockAndroidCameraCamerax extends AndroidCameraCameraX {
final MockProcessCameraProvider testProcessCameraProvider =
MockProcessCameraProvider();
final MockPreview testPreview = MockPreview();
final MockCameraSelector mockBackCameraSelector = MockCameraSelector();
final MockCameraSelector mockFrontCameraSelector = MockCameraSelector();
final MockCameraSelector testCameraSelector = MockCameraSelector();

@override
Expand All @@ -327,7 +386,14 @@ class MockAndroidCameraCamerax extends AndroidCameraCameraX {

@override
CameraSelector createCameraSelector(int cameraSelectorLensDirection) {
return testCameraSelector;
switch(cameraSelectorLensDirection) {
case CameraSelector.LENS_FACING_FRONT:
return mockFrontCameraSelector;
case CameraSelector.LENS_FACING_BACK:
return mockBackCameraSelector;
default:
return testCameraSelector;
}
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import 'dart:async' as _i8;

import 'package:camera_android_camerax/src/camera.dart' as _i5;
import 'package:camera_android_camerax/src/camera_info.dart' as _i9;
import 'package:camera_android_camerax/src/camera_selector.dart' as _i7;
import 'package:camera_android_camerax/src/camera_info.dart' as _i7;
import 'package:camera_android_camerax/src/camera_selector.dart' as _i9;
import 'package:camera_android_camerax/src/camerax_library.g.dart' as _i4;
import 'package:camera_android_camerax/src/preview.dart' as _i10;
import 'package:camera_android_camerax/src/process_camera_provider.dart'
Expand Down Expand Up @@ -276,21 +276,36 @@ class MockBuildContext extends _i1.Mock implements _i2.BuildContext {
/// See the documentation for Mockito's code generation for more information.
class MockCamera extends _i1.Mock implements _i5.Camera {}

/// A class which mocks [CameraInfo].
///
/// See the documentation for Mockito's code generation for more information.
class MockCameraInfo extends _i1.Mock implements _i7.CameraInfo {
@override
_i8.Future<int> getSensorRotationDegrees() => (super.noSuchMethod(
Invocation.method(
#getSensorRotationDegrees,
[],
),
returnValue: _i8.Future<int>.value(0),
returnValueForMissingStub: _i8.Future<int>.value(0),
) as _i8.Future<int>);
}

/// A class which mocks [CameraSelector].
///
/// See the documentation for Mockito's code generation for more information.
class MockCameraSelector extends _i1.Mock implements _i7.CameraSelector {
class MockCameraSelector extends _i1.Mock implements _i9.CameraSelector {
@override
_i8.Future<List<_i9.CameraInfo>> filter(List<_i9.CameraInfo>? cameraInfos) =>
_i8.Future<List<_i7.CameraInfo>> filter(List<_i7.CameraInfo>? cameraInfos) =>
(super.noSuchMethod(
Invocation.method(
#filter,
[cameraInfos],
),
returnValue: _i8.Future<List<_i9.CameraInfo>>.value(<_i9.CameraInfo>[]),
returnValue: _i8.Future<List<_i7.CameraInfo>>.value(<_i7.CameraInfo>[]),
returnValueForMissingStub:
_i8.Future<List<_i9.CameraInfo>>.value(<_i9.CameraInfo>[]),
) as _i8.Future<List<_i9.CameraInfo>>);
_i8.Future<List<_i7.CameraInfo>>.value(<_i7.CameraInfo>[]),
) as _i8.Future<List<_i7.CameraInfo>>);
}

/// A class which mocks [Preview].
Expand Down Expand Up @@ -344,19 +359,19 @@ class MockPreview extends _i1.Mock implements _i10.Preview {
class MockProcessCameraProvider extends _i1.Mock
implements _i11.ProcessCameraProvider {
@override
_i8.Future<List<_i9.CameraInfo>> getAvailableCameraInfos() =>
_i8.Future<List<_i7.CameraInfo>> getAvailableCameraInfos() =>
(super.noSuchMethod(
Invocation.method(
#getAvailableCameraInfos,
[],
),
returnValue: _i8.Future<List<_i9.CameraInfo>>.value(<_i9.CameraInfo>[]),
returnValue: _i8.Future<List<_i7.CameraInfo>>.value(<_i7.CameraInfo>[]),
returnValueForMissingStub:
_i8.Future<List<_i9.CameraInfo>>.value(<_i9.CameraInfo>[]),
) as _i8.Future<List<_i9.CameraInfo>>);
_i8.Future<List<_i7.CameraInfo>>.value(<_i7.CameraInfo>[]),
) as _i8.Future<List<_i7.CameraInfo>>);
@override
_i8.Future<_i5.Camera> bindToLifecycle(
_i7.CameraSelector? cameraSelector,
_i9.CameraSelector? cameraSelector,
List<_i12.UseCase>? useCases,
) =>
(super.noSuchMethod(
Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.