Skip to content

Commit 7a9e9ce

Browse files
authored
Fixed Camera Switching Bug (#9671)
Fixed camera switching issue where phones with multiple back cameras could not correctly switch to some other chosen camera. Fixed by specifying a camera via its CameraInfo instead of its direction. Fixes flutter/flutter#164963 ## 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 d914120 commit 7a9e9ce

File tree

12 files changed

+446
-9
lines changed

12 files changed

+446
-9
lines changed

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.19+1
2+
3+
* Fixes incorrect camera switching by selecting a camera via its CameraInfo.
4+
15
## 0.6.19
26

37
* Changes target rotation of captured images to current default display rotation to fix captured

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import androidx.camera.core.CameraInfo;
1010
import androidx.camera.core.CameraSelector;
1111
import androidx.camera.core.ExperimentalLensFacing;
12+
import java.util.Collections;
1213
import java.util.List;
1314

1415
/**
@@ -24,7 +25,8 @@ class CameraSelectorProxyApi extends PigeonApiCameraSelector {
2425
@ExperimentalLensFacing
2526
@NonNull
2627
@Override
27-
public CameraSelector pigeon_defaultConstructor(@Nullable LensFacing requireLensFacing) {
28+
public CameraSelector pigeon_defaultConstructor(
29+
@Nullable LensFacing requireLensFacing, @Nullable CameraInfo cameraInfoForFilter) {
2830
final CameraSelector.Builder builder = new CameraSelector.Builder();
2931
if (requireLensFacing != null) {
3032
switch (requireLensFacing) {
@@ -42,6 +44,9 @@ public CameraSelector pigeon_defaultConstructor(@Nullable LensFacing requireLens
4244
break;
4345
}
4446
}
47+
if (cameraInfoForFilter != null) {
48+
builder.addCameraFilter(cameraInfos -> Collections.singletonList(cameraInfoForFilter));
49+
}
4550
return builder.build();
4651
}
4752

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2027,7 +2027,8 @@ abstract class PigeonApiCameraSelector(
20272027
open val pigeonRegistrar: CameraXLibraryPigeonProxyApiRegistrar
20282028
) {
20292029
abstract fun pigeon_defaultConstructor(
2030-
requireLensFacing: LensFacing?
2030+
requireLensFacing: LensFacing?,
2031+
cameraInfoForFilter: androidx.camera.core.CameraInfo?
20312032
): androidx.camera.core.CameraSelector
20322033

20332034
/** A static `CameraSelector` that selects the default back facing camera. */
@@ -2057,10 +2058,12 @@ abstract class PigeonApiCameraSelector(
20572058
val args = message as List<Any?>
20582059
val pigeon_identifierArg = args[0] as Long
20592060
val requireLensFacingArg = args[1] as LensFacing?
2061+
val cameraInfoForFilterArg = args[2] as androidx.camera.core.CameraInfo?
20602062
val wrapped: List<Any?> =
20612063
try {
20622064
api.pigeonRegistrar.instanceManager.addDartCreatedInstance(
2063-
api.pigeon_defaultConstructor(requireLensFacingArg), pigeon_identifierArg)
2065+
api.pigeon_defaultConstructor(requireLensFacingArg, cameraInfoForFilterArg),
2066+
pigeon_identifierArg)
20642067
listOf(null)
20652068
} catch (exception: Throwable) {
20662069
CameraXLibraryPigeonUtils.wrapError(exception)

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import androidx.camera.core.CameraInfo;
1212
import androidx.camera.core.CameraSelector;
13+
import java.util.ArrayList;
1314
import java.util.Collections;
1415
import java.util.List;
1516
import org.junit.Test;
@@ -18,13 +19,30 @@ public class CameraSelectorTest {
1819
@Test
1920
public void pigeon_defaultConstructor_createsCameraSelectorInstanceWithLensFacing() {
2021
final PigeonApiCameraSelector api = new TestProxyApiRegistrar().getPigeonApiCameraSelector();
21-
2222
final CameraSelector selector =
23-
api.pigeon_defaultConstructor(io.flutter.plugins.camerax.LensFacing.FRONT);
23+
api.pigeon_defaultConstructor(io.flutter.plugins.camerax.LensFacing.FRONT, null);
2424

2525
assertEquals(selector.getLensFacing(), (Integer) CameraSelector.LENS_FACING_FRONT);
2626
}
2727

28+
@Test
29+
public void pigeon_defaultConstructor_createsCameraSelectorInstanceWithCameraInfo() {
30+
final PigeonApiCameraSelector api = new TestProxyApiRegistrar().getPigeonApiCameraSelector();
31+
final androidx.camera.core.CameraInfo cameraInfo = mock(CameraInfo.class);
32+
final androidx.camera.core.CameraInfo cameraInfoToSelect = mock(CameraInfo.class);
33+
34+
final CameraSelector selector = api.pigeon_defaultConstructor(null, cameraInfoToSelect);
35+
36+
final List<androidx.camera.core.CameraInfo> cameraInfosList = new ArrayList<>();
37+
cameraInfosList.add(cameraInfo);
38+
cameraInfosList.add(cameraInfoToSelect);
39+
40+
final List<androidx.camera.core.CameraInfo> filteredCameraInfosList =
41+
selector.filter(new ArrayList<>(cameraInfosList));
42+
assertEquals(1, filteredCameraInfosList.size());
43+
assertEquals(cameraInfoToSelect, filteredCameraInfosList.get(0));
44+
}
45+
2846
@Test
2947
public void filter_callsFilterWithMethodParameters() {
3048
final PigeonApiCameraSelector api = new TestProxyApiRegistrar().getPigeonApiCameraSelector();

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,9 @@ class AndroidCameraCameraX extends CameraPlatform {
266266
@visibleForTesting
267267
late bool enableRecordingAudio;
268268

269+
/// A map to associate a [CameraInfo] with its camera name.
270+
final Map<String, CameraInfo> _savedCameras = <String, CameraInfo>{};
271+
269272
/// Returns list of all available cameras and their descriptions.
270273
@override
271274
Future<List<CameraDescription>> availableCameras() async {
@@ -302,6 +305,8 @@ class AndroidCameraCameraX extends CameraPlatform {
302305
cameraName = 'Camera $cameraCount';
303306
cameraCount++;
304307

308+
_savedCameras[cameraName] = cameraInfo;
309+
305310
// TODO(camsim99): Use camera ID retrieved from Camera2CameraInfo as
306311
// camera name: https://github.com/flutter/flutter/issues/147545.
307312
cameraDescriptions.add(
@@ -357,13 +362,15 @@ class AndroidCameraCameraX extends CameraPlatform {
357362
if (error != null) {
358363
throw CameraException(error.errorCode, error.description);
359364
}
365+
// Choose CameraInfo to create CameraSelector by name associated with desired camera.
366+
final CameraInfo? chosenCameraInfo = _savedCameras[cameraDescription.name];
360367

361368
// Save CameraSelector that matches cameraDescription.
362369
final LensFacing cameraSelectorLensDirection =
363370
_getCameraSelectorLensDirection(cameraDescription.lensDirection);
364371
cameraIsFrontFacing = cameraSelectorLensDirection == LensFacing.front;
365372
cameraSelector = proxy.newCameraSelector(
366-
requireLensFacing: cameraSelectorLensDirection,
373+
cameraInfoForFilter: chosenCameraInfo,
367374
);
368375
// Start listening for device orientation changes preceding camera creation.
369376
unawaited(

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1964,6 +1964,7 @@ class CameraSelector extends PigeonInternalProxyApiBaseClass {
19641964
super.pigeon_binaryMessenger,
19651965
super.pigeon_instanceManager,
19661966
LensFacing? requireLensFacing,
1967+
CameraInfo? cameraInfoForFilter,
19671968
}) {
19681969
final int pigeonVar_instanceIdentifier = pigeon_instanceManager
19691970
.addDartCreatedInstance(this);
@@ -1979,7 +1980,11 @@ class CameraSelector extends PigeonInternalProxyApiBaseClass {
19791980
binaryMessenger: pigeonVar_binaryMessenger,
19801981
);
19811982
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
1982-
<Object?>[pigeonVar_instanceIdentifier, requireLensFacing],
1983+
<Object?>[
1984+
pigeonVar_instanceIdentifier,
1985+
requireLensFacing,
1986+
cameraInfoForFilter,
1987+
],
19831988
);
19841989
() async {
19851990
final List<Object?>? pigeonVar_replyList =

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class CameraXProxy {
108108
/// Constructs [CameraSelector].
109109
final CameraSelector Function({
110110
LensFacing? requireLensFacing,
111+
CameraInfo? cameraInfoForFilter,
111112
BinaryMessenger? pigeon_binaryMessenger,
112113
PigeonInstanceManager? pigeon_instanceManager,
113114
})

packages/camera/camera_android_camerax/pigeons/camerax_library.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,10 @@ enum LensFacing {
290290
),
291291
)
292292
abstract class CameraSelector {
293-
CameraSelector(LensFacing? requireLensFacing);
293+
CameraSelector(
294+
LensFacing? requireLensFacing,
295+
CameraInfo? cameraInfoForFilter,
296+
);
294297

295298
/// A static `CameraSelector` that selects the default back facing camera.
296299
@static

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.19
5+
version: 0.6.19+1
66

77
environment:
88
sdk: ^3.7.0

0 commit comments

Comments
 (0)