Skip to content

Commit d878913

Browse files
authored
[camera_android_camerax] Retrieve lens direction from CameraX directly (#10847)
Changes manual detection of the camera direction via filtering to querying it directly from the camera info. Fixes flutter/flutter#118730. ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent ed3ff4c commit d878913

12 files changed

Lines changed: 151 additions & 100 deletions

File tree

packages/camera/camera_android_camerax/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.6.29
2+
3+
* Modifies lens direction logic to request the value from CameraX directly versus manual detection.
4+
15
## 0.6.28
26

37
* Adds more descriptive error to camera error stream when image capture fails.

packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoProxyApi.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
package io.flutter.plugins.camerax;
66

77
import androidx.annotation.NonNull;
8+
import androidx.annotation.OptIn;
89
import androidx.camera.core.CameraInfo;
10+
import androidx.camera.core.CameraSelector;
11+
import androidx.camera.core.ExperimentalLensFacing;
912
import androidx.camera.core.ExposureState;
1013

1114
/**
@@ -23,6 +26,22 @@ public long sensorRotationDegrees(CameraInfo pigeonInstance) {
2326
return pigeonInstance.getSensorRotationDegrees();
2427
}
2528

29+
@Override
30+
@OptIn(markerClass = ExperimentalLensFacing.class)
31+
public LensFacing lensFacing(CameraInfo pigeonInstance) {
32+
int lensFacing = pigeonInstance.getLensFacing();
33+
switch (lensFacing) {
34+
case CameraSelector.LENS_FACING_FRONT:
35+
return LensFacing.FRONT;
36+
case CameraSelector.LENS_FACING_BACK:
37+
return LensFacing.BACK;
38+
case CameraSelector.LENS_FACING_EXTERNAL:
39+
return LensFacing.EXTERNAL;
40+
default:
41+
return LensFacing.UNKNOWN;
42+
}
43+
}
44+
2645
@NonNull
2746
@Override
2847
public ExposureState exposureState(CameraInfo pigeonInstance) {

packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraXLibrary.g.kt

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,6 +2181,9 @@ abstract class PigeonApiCameraInfo(
21812181
*/
21822182
abstract fun sensorRotationDegrees(pigeon_instance: androidx.camera.core.CameraInfo): Long
21832183

2184+
/** Returns the lens facing of this camera. */
2185+
abstract fun lensFacing(pigeon_instance: androidx.camera.core.CameraInfo): LensFacing
2186+
21842187
/** Returns a ExposureState. */
21852188
abstract fun exposureState(
21862189
pigeon_instance: androidx.camera.core.CameraInfo
@@ -2263,23 +2266,26 @@ abstract class PigeonApiCameraInfo(
22632266
val pigeon_identifierArg =
22642267
pigeonRegistrar.instanceManager.addHostCreatedInstance(pigeon_instanceArg)
22652268
val sensorRotationDegreesArg = sensorRotationDegrees(pigeon_instanceArg)
2269+
val lensFacingArg = lensFacing(pigeon_instanceArg)
22662270
val exposureStateArg = exposureState(pigeon_instanceArg)
22672271
val binaryMessenger = pigeonRegistrar.binaryMessenger
22682272
val codec = pigeonRegistrar.codec
22692273
val channelName = "dev.flutter.pigeon.camera_android_camerax.CameraInfo.pigeon_newInstance"
22702274
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
2271-
channel.send(listOf(pigeon_identifierArg, sensorRotationDegreesArg, exposureStateArg)) {
2272-
if (it is List<*>) {
2273-
if (it.size > 1) {
2274-
callback(
2275-
Result.failure(CameraXError(it[0] as String, it[1] as String, it[2] as String?)))
2276-
} else {
2277-
callback(Result.success(Unit))
2275+
channel.send(
2276+
listOf(pigeon_identifierArg, sensorRotationDegreesArg, lensFacingArg, exposureStateArg)) {
2277+
if (it is List<*>) {
2278+
if (it.size > 1) {
2279+
callback(
2280+
Result.failure(
2281+
CameraXError(it[0] as String, it[1] as String, it[2] as String?)))
2282+
} else {
2283+
callback(Result.success(Unit))
2284+
}
2285+
} else {
2286+
callback(Result.failure(CameraXLibraryPigeonUtils.createConnectionError(channelName)))
2287+
}
22782288
}
2279-
} else {
2280-
callback(Result.failure(CameraXLibraryPigeonUtils.createConnectionError(channelName)))
2281-
}
2282-
}
22832289
}
22842290
}
22852291
}

packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraInfoTest.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@
99
import static org.mockito.Mockito.when;
1010

1111
import androidx.camera.core.CameraInfo;
12+
import androidx.camera.core.CameraSelector;
1213
import androidx.camera.core.CameraState;
1314
import androidx.camera.core.ExposureState;
1415
import androidx.camera.core.ZoomState;
1516
import androidx.lifecycle.LiveData;
17+
import java.util.Arrays;
18+
import java.util.List;
1619
import org.junit.Test;
1720

1821
public class CameraInfoTest {
1922
@Test
20-
public void getSensorRotationDegrees_makesCallToRetrieveSensorRotationDegrees() {
23+
public void sensorRotationDegrees_makesCallToRetrieveSensorRotationDegrees() {
2124
final PigeonApiCameraInfo api = new TestProxyApiRegistrar().getPigeonApiCameraInfo();
2225

2326
final CameraInfo instance = mock(CameraInfo.class);
@@ -27,6 +30,41 @@ public void getSensorRotationDegrees_makesCallToRetrieveSensorRotationDegrees()
2730
assertEquals(value, api.sensorRotationDegrees(instance));
2831
}
2932

33+
@Test
34+
public void lensFacing_makesCallToRetrieveLensFacing() {
35+
final PigeonApiCameraInfo api = new TestProxyApiRegistrar().getPigeonApiCameraInfo();
36+
37+
final CameraInfo instance = mock(CameraInfo.class);
38+
List<Integer> testedLensFacingValues =
39+
Arrays.asList(
40+
CameraSelector.LENS_FACING_BACK,
41+
CameraSelector.LENS_FACING_FRONT,
42+
CameraSelector.LENS_FACING_EXTERNAL,
43+
CameraSelector.LENS_FACING_UNKNOWN);
44+
45+
for (int testedLensFacingValue : testedLensFacingValues) {
46+
when(instance.getLensFacing()).thenReturn(testedLensFacingValue);
47+
48+
LensFacing expected;
49+
switch (testedLensFacingValue) {
50+
case CameraSelector.LENS_FACING_BACK:
51+
expected = LensFacing.BACK;
52+
break;
53+
case CameraSelector.LENS_FACING_FRONT:
54+
expected = LensFacing.FRONT;
55+
break;
56+
case CameraSelector.LENS_FACING_EXTERNAL:
57+
expected = LensFacing.EXTERNAL;
58+
break;
59+
default:
60+
expected = LensFacing.UNKNOWN;
61+
break;
62+
}
63+
64+
assertEquals(expected, api.lensFacing(instance));
65+
}
66+
}
67+
3068
@SuppressWarnings("unchecked")
3169
@Test
3270
public void getCameraState_makesCallToRetrieveLiveCameraState() {

packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -307,19 +307,17 @@ class AndroidCameraCameraX extends CameraPlatform {
307307
String? cameraName;
308308

309309
for (final cameraInfo in cameraInfos) {
310-
// Determine the lens direction by filtering the CameraInfo
311-
// TODO(gmackall): replace this with call to CameraInfo.getLensFacing when changes containing that method are available
312-
if ((await CameraSelector(
313-
requireLensFacing: LensFacing.back,
314-
).filter(<CameraInfo>[cameraInfo])).isNotEmpty) {
315-
cameraLensDirection = CameraLensDirection.back;
316-
} else if ((await CameraSelector(
317-
requireLensFacing: LensFacing.front,
318-
).filter(<CameraInfo>[cameraInfo])).isNotEmpty) {
319-
cameraLensDirection = CameraLensDirection.front;
320-
} else {
321-
//Skip this CameraInfo as its lens direction is unknown
322-
continue;
310+
final LensFacing lensFacing = cameraInfo.lensFacing;
311+
switch (lensFacing) {
312+
case LensFacing.front:
313+
cameraLensDirection = CameraLensDirection.front;
314+
case LensFacing.back:
315+
cameraLensDirection = CameraLensDirection.back;
316+
case LensFacing.external:
317+
cameraLensDirection = CameraLensDirection.external;
318+
case LensFacing.unknown:
319+
// Skip this CameraInfo as its lens direction is unknown
320+
continue;
323321
}
324322

325323
cameraSensorOrientation = cameraInfo.sensorRotationDegrees;

packages/camera/camera_android_camerax/lib/src/camerax_library.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,14 @@ void setUpGenerics({BinaryMessenger? pigeonBinaryMessenger}) {
5656

5757
camerax.CameraInfo.pigeon_setUpMessageHandlers(
5858
pigeon_newInstance:
59-
(int sensorRotationDegrees, camerax.ExposureState exposureState) {
59+
(
60+
int sensorRotationDegrees,
61+
camerax.LensFacing lensFacing,
62+
camerax.ExposureState exposureState,
63+
) {
6064
return CameraInfo.detached(
6165
sensorRotationDegrees: sensorRotationDegrees,
66+
lensFacing: lensFacing,
6267
exposureState: exposureState,
6368
pigeon_binaryMessenger: pigeonBinaryMessenger,
6469
);
@@ -101,6 +106,7 @@ class CameraInfo extends camerax.CameraInfo {
101106
/// create copies for an [PigeonInstanceManager].
102107
CameraInfo.detached({
103108
required super.sensorRotationDegrees,
109+
required super.lensFacing,
104110
required super.exposureState,
105111
// ignore: non_constant_identifier_names
106112
super.pigeon_binaryMessenger,
@@ -121,6 +127,7 @@ class CameraInfo extends camerax.CameraInfo {
121127
CameraInfo pigeon_copy() {
122128
return CameraInfo.detached(
123129
sensorRotationDegrees: sensorRotationDegrees,
130+
lensFacing: lensFacing,
124131
exposureState: exposureState,
125132
pigeon_binaryMessenger: pigeon_binaryMessenger,
126133
);

packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2107,6 +2107,7 @@ class CameraInfo extends PigeonInternalProxyApiBaseClass {
21072107
super.pigeon_binaryMessenger,
21082108
super.pigeon_instanceManager,
21092109
required this.sensorRotationDegrees,
2110+
required this.lensFacing,
21102111
required this.exposureState,
21112112
});
21122113

@@ -2117,14 +2118,21 @@ class CameraInfo extends PigeonInternalProxyApiBaseClass {
21172118
/// (default) orientation.
21182119
final int sensorRotationDegrees;
21192120

2121+
/// Returns the lens facing of this camera.
2122+
final LensFacing lensFacing;
2123+
21202124
/// Returns a ExposureState.
21212125
final ExposureState exposureState;
21222126

21232127
static void pigeon_setUpMessageHandlers({
21242128
bool pigeon_clearHandlers = false,
21252129
BinaryMessenger? pigeon_binaryMessenger,
21262130
PigeonInstanceManager? pigeon_instanceManager,
2127-
CameraInfo Function(int sensorRotationDegrees, ExposureState exposureState)?
2131+
CameraInfo Function(
2132+
int sensorRotationDegrees,
2133+
LensFacing lensFacing,
2134+
ExposureState exposureState,
2135+
)?
21282136
pigeon_newInstance,
21292137
}) {
21302138
final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
@@ -2157,7 +2165,12 @@ class CameraInfo extends PigeonInternalProxyApiBaseClass {
21572165
arg_sensorRotationDegrees != null,
21582166
'Argument for dev.flutter.pigeon.camera_android_camerax.CameraInfo.pigeon_newInstance was null, expected non-null int.',
21592167
);
2160-
final ExposureState? arg_exposureState = (args[2] as ExposureState?);
2168+
final LensFacing? arg_lensFacing = (args[2] as LensFacing?);
2169+
assert(
2170+
arg_lensFacing != null,
2171+
'Argument for dev.flutter.pigeon.camera_android_camerax.CameraInfo.pigeon_newInstance was null, expected non-null LensFacing.',
2172+
);
2173+
final ExposureState? arg_exposureState = (args[3] as ExposureState?);
21612174
assert(
21622175
arg_exposureState != null,
21632176
'Argument for dev.flutter.pigeon.camera_android_camerax.CameraInfo.pigeon_newInstance was null, expected non-null ExposureState.',
@@ -2167,12 +2180,14 @@ class CameraInfo extends PigeonInternalProxyApiBaseClass {
21672180
.addHostCreatedInstance(
21682181
pigeon_newInstance?.call(
21692182
arg_sensorRotationDegrees!,
2183+
arg_lensFacing!,
21702184
arg_exposureState!,
21712185
) ??
21722186
CameraInfo.pigeon_detached(
21732187
pigeon_binaryMessenger: pigeon_binaryMessenger,
21742188
pigeon_instanceManager: pigeon_instanceManager,
21752189
sensorRotationDegrees: arg_sensorRotationDegrees!,
2190+
lensFacing: arg_lensFacing!,
21762191
exposureState: arg_exposureState!,
21772192
),
21782193
arg_pigeon_instanceIdentifier!,
@@ -2264,6 +2279,7 @@ class CameraInfo extends PigeonInternalProxyApiBaseClass {
22642279
pigeon_binaryMessenger: pigeon_binaryMessenger,
22652280
pigeon_instanceManager: pigeon_instanceManager,
22662281
sensorRotationDegrees: sensorRotationDegrees,
2282+
lensFacing: lensFacing,
22672283
exposureState: exposureState,
22682284
);
22692285
}

packages/camera/camera_android_camerax/pigeons/camerax_library.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ abstract class CameraInfo {
251251
/// (default) orientation.
252252
late int sensorRotationDegrees;
253253

254+
/// Returns the lens direction of this camera.
255+
late LensFacing lensFacing;
256+
254257
/// Returns a ExposureState.
255258
late ExposureState exposureState;
256259

packages/camera/camera_android_camerax/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: camera_android_camerax
22
description: Android implementation of the camera plugin using the CameraX library.
33
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android_camerax
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
5-
version: 0.6.28
5+
version: 0.6.29
66

77
environment:
88
sdk: ^3.9.0

0 commit comments

Comments
 (0)