Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit dc0d3a0

Browse files
authored
[camerax] Wrap methods necessary for preview implementation (#7046)
* Add code needed from proof of concept * Add test files, delete unecessary method * Add tests, remove unecessary code * Fix analyze * Update changelog * Cleanup: * Cleanup and add switch * Finish todo * Add onCameraError * Fix pigeon file * Add method for releasing flutter texture and cleanup surface logic * Add test for release method * Add dart test * Update changelog * Modify flutter api names to avoid stack overflow * Cleanup * Fix tests * Delete space * Address review 1 * Update switch * Add annotations and constants in tests * Reset verification behavior
1 parent eb0a6b5 commit dc0d3a0

18 files changed

+1413
-15
lines changed

packages/camera/camera_android_camerax/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
* Adds Camera and UseCase classes, along with methods for binding UseCases to a lifecycle with the ProcessCameraProvider.
99
* Bump CameraX version to 1.3.0-alpha03 and Kotlin version to 1.8.0.
1010
* Changes instance manager to allow the separate creation of identical objects.
11+
* Adds Preview and Surface classes, along with other methods needed to implement camera preview.

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ void setUp(BinaryMessenger binaryMessenger, Context context, TextureRegistry tex
4949
binaryMessenger, processCameraProviderHostApi);
5050
systemServicesHostApi = new SystemServicesHostApiImpl(binaryMessenger, instanceManager);
5151
GeneratedCameraXLibrary.SystemServicesHostApi.setup(binaryMessenger, systemServicesHostApi);
52+
GeneratedCameraXLibrary.PreviewHostApi.setup(
53+
binaryMessenger, new PreviewHostApiImpl(binaryMessenger, instanceManager, textureRegistry));
5254
}
5355

5456
@Override

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@
55
package io.flutter.plugins.camerax;
66

77
import android.app.Activity;
8+
import android.graphics.SurfaceTexture;
9+
import android.view.Surface;
10+
import androidx.annotation.NonNull;
811
import androidx.camera.core.CameraSelector;
12+
import androidx.camera.core.Preview;
13+
import io.flutter.plugin.common.BinaryMessenger;
914

15+
/** Utility class used to create CameraX-related objects primarily for testing purposes. */
1016
public class CameraXProxy {
1117
public CameraSelector.Builder createCameraSelectorBuilder() {
1218
return new CameraSelector.Builder();
@@ -17,10 +23,29 @@ public CameraPermissionsManager createCameraPermissionsManager() {
1723
}
1824

1925
public DeviceOrientationManager createDeviceOrientationManager(
20-
Activity activity,
21-
Boolean isFrontFacing,
22-
int sensorOrientation,
23-
DeviceOrientationManager.DeviceOrientationChangeCallback callback) {
26+
@NonNull Activity activity,
27+
@NonNull Boolean isFrontFacing,
28+
@NonNull int sensorOrientation,
29+
@NonNull DeviceOrientationManager.DeviceOrientationChangeCallback callback) {
2430
return new DeviceOrientationManager(activity, isFrontFacing, sensorOrientation, callback);
2531
}
32+
33+
public Preview.Builder createPreviewBuilder() {
34+
return new Preview.Builder();
35+
}
36+
37+
public Surface createSurface(@NonNull SurfaceTexture surfaceTexture) {
38+
return new Surface(surfaceTexture);
39+
}
40+
41+
/**
42+
* Creates an instance of the {@code SystemServicesFlutterApiImpl}.
43+
*
44+
* <p>Included in this class to utilize the callback methods it provides, e.g. {@code
45+
* onCameraError(String)}.
46+
*/
47+
public SystemServicesFlutterApiImpl createSystemServicesFlutterApiImpl(
48+
@NonNull BinaryMessenger binaryMessenger) {
49+
return new SystemServicesFlutterApiImpl(binaryMessenger);
50+
}
2651
}

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

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,82 @@
2525
@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"})
2626
public class GeneratedCameraXLibrary {
2727

28+
/** Generated class from Pigeon that represents data sent in messages. */
29+
public static class ResolutionInfo {
30+
private @NonNull Long width;
31+
32+
public @NonNull Long getWidth() {
33+
return width;
34+
}
35+
36+
public void setWidth(@NonNull Long setterArg) {
37+
if (setterArg == null) {
38+
throw new IllegalStateException("Nonnull field \"width\" is null.");
39+
}
40+
this.width = setterArg;
41+
}
42+
43+
private @NonNull Long height;
44+
45+
public @NonNull Long getHeight() {
46+
return height;
47+
}
48+
49+
public void setHeight(@NonNull Long setterArg) {
50+
if (setterArg == null) {
51+
throw new IllegalStateException("Nonnull field \"height\" is null.");
52+
}
53+
this.height = setterArg;
54+
}
55+
56+
/** Constructor is private to enforce null safety; use Builder. */
57+
private ResolutionInfo() {}
58+
59+
public static final class Builder {
60+
private @Nullable Long width;
61+
62+
public @NonNull Builder setWidth(@NonNull Long setterArg) {
63+
this.width = setterArg;
64+
return this;
65+
}
66+
67+
private @Nullable Long height;
68+
69+
public @NonNull Builder setHeight(@NonNull Long setterArg) {
70+
this.height = setterArg;
71+
return this;
72+
}
73+
74+
public @NonNull ResolutionInfo build() {
75+
ResolutionInfo pigeonReturn = new ResolutionInfo();
76+
pigeonReturn.setWidth(width);
77+
pigeonReturn.setHeight(height);
78+
return pigeonReturn;
79+
}
80+
}
81+
82+
@NonNull
83+
Map<String, Object> toMap() {
84+
Map<String, Object> toMapResult = new HashMap<>();
85+
toMapResult.put("width", width);
86+
toMapResult.put("height", height);
87+
return toMapResult;
88+
}
89+
90+
static @NonNull ResolutionInfo fromMap(@NonNull Map<String, Object> map) {
91+
ResolutionInfo pigeonResult = new ResolutionInfo();
92+
Object width = map.get("width");
93+
pigeonResult.setWidth(
94+
(width == null) ? null : ((width instanceof Integer) ? (Integer) width : (Long) width));
95+
Object height = map.get("height");
96+
pigeonResult.setHeight(
97+
(height == null)
98+
? null
99+
: ((height instanceof Integer) ? (Integer) height : (Long) height));
100+
return pigeonResult;
101+
}
102+
}
103+
28104
/** Generated class from Pigeon that represents data sent in messages. */
29105
public static class CameraPermissionsErrorData {
30106
private @NonNull String errorCode;
@@ -843,6 +919,185 @@ public void onDeviceOrientationChanged(@NonNull String orientationArg, Reply<Voi
843919
callback.reply(null);
844920
});
845921
}
922+
923+
public void onCameraError(@NonNull String errorDescriptionArg, Reply<Void> callback) {
924+
BasicMessageChannel<Object> channel =
925+
new BasicMessageChannel<>(
926+
binaryMessenger,
927+
"dev.flutter.pigeon.SystemServicesFlutterApi.onCameraError",
928+
getCodec());
929+
channel.send(
930+
new ArrayList<Object>(Arrays.asList(errorDescriptionArg)),
931+
channelReply -> {
932+
callback.reply(null);
933+
});
934+
}
935+
}
936+
937+
private static class PreviewHostApiCodec extends StandardMessageCodec {
938+
public static final PreviewHostApiCodec INSTANCE = new PreviewHostApiCodec();
939+
940+
private PreviewHostApiCodec() {}
941+
942+
@Override
943+
protected Object readValueOfType(byte type, ByteBuffer buffer) {
944+
switch (type) {
945+
case (byte) 128:
946+
return ResolutionInfo.fromMap((Map<String, Object>) readValue(buffer));
947+
948+
case (byte) 129:
949+
return ResolutionInfo.fromMap((Map<String, Object>) readValue(buffer));
950+
951+
default:
952+
return super.readValueOfType(type, buffer);
953+
}
954+
}
955+
956+
@Override
957+
protected void writeValue(ByteArrayOutputStream stream, Object value) {
958+
if (value instanceof ResolutionInfo) {
959+
stream.write(128);
960+
writeValue(stream, ((ResolutionInfo) value).toMap());
961+
} else if (value instanceof ResolutionInfo) {
962+
stream.write(129);
963+
writeValue(stream, ((ResolutionInfo) value).toMap());
964+
} else {
965+
super.writeValue(stream, value);
966+
}
967+
}
968+
}
969+
970+
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
971+
public interface PreviewHostApi {
972+
void create(
973+
@NonNull Long identifier,
974+
@Nullable Long rotation,
975+
@Nullable ResolutionInfo targetResolution);
976+
977+
@NonNull
978+
Long setSurfaceProvider(@NonNull Long identifier);
979+
980+
void releaseFlutterSurfaceTexture();
981+
982+
@NonNull
983+
ResolutionInfo getResolutionInfo(@NonNull Long identifier);
984+
985+
/** The codec used by PreviewHostApi. */
986+
static MessageCodec<Object> getCodec() {
987+
return PreviewHostApiCodec.INSTANCE;
988+
}
989+
990+
/** Sets up an instance of `PreviewHostApi` to handle messages through the `binaryMessenger`. */
991+
static void setup(BinaryMessenger binaryMessenger, PreviewHostApi api) {
992+
{
993+
BasicMessageChannel<Object> channel =
994+
new BasicMessageChannel<>(
995+
binaryMessenger, "dev.flutter.pigeon.PreviewHostApi.create", getCodec());
996+
if (api != null) {
997+
channel.setMessageHandler(
998+
(message, reply) -> {
999+
Map<String, Object> wrapped = new HashMap<>();
1000+
try {
1001+
ArrayList<Object> args = (ArrayList<Object>) message;
1002+
Number identifierArg = (Number) args.get(0);
1003+
if (identifierArg == null) {
1004+
throw new NullPointerException("identifierArg unexpectedly null.");
1005+
}
1006+
Number rotationArg = (Number) args.get(1);
1007+
ResolutionInfo targetResolutionArg = (ResolutionInfo) args.get(2);
1008+
api.create(
1009+
(identifierArg == null) ? null : identifierArg.longValue(),
1010+
(rotationArg == null) ? null : rotationArg.longValue(),
1011+
targetResolutionArg);
1012+
wrapped.put("result", null);
1013+
} catch (Error | RuntimeException exception) {
1014+
wrapped.put("error", wrapError(exception));
1015+
}
1016+
reply.reply(wrapped);
1017+
});
1018+
} else {
1019+
channel.setMessageHandler(null);
1020+
}
1021+
}
1022+
{
1023+
BasicMessageChannel<Object> channel =
1024+
new BasicMessageChannel<>(
1025+
binaryMessenger,
1026+
"dev.flutter.pigeon.PreviewHostApi.setSurfaceProvider",
1027+
getCodec());
1028+
if (api != null) {
1029+
channel.setMessageHandler(
1030+
(message, reply) -> {
1031+
Map<String, Object> wrapped = new HashMap<>();
1032+
try {
1033+
ArrayList<Object> args = (ArrayList<Object>) message;
1034+
Number identifierArg = (Number) args.get(0);
1035+
if (identifierArg == null) {
1036+
throw new NullPointerException("identifierArg unexpectedly null.");
1037+
}
1038+
Long output =
1039+
api.setSurfaceProvider(
1040+
(identifierArg == null) ? null : identifierArg.longValue());
1041+
wrapped.put("result", output);
1042+
} catch (Error | RuntimeException exception) {
1043+
wrapped.put("error", wrapError(exception));
1044+
}
1045+
reply.reply(wrapped);
1046+
});
1047+
} else {
1048+
channel.setMessageHandler(null);
1049+
}
1050+
}
1051+
{
1052+
BasicMessageChannel<Object> channel =
1053+
new BasicMessageChannel<>(
1054+
binaryMessenger,
1055+
"dev.flutter.pigeon.PreviewHostApi.releaseFlutterSurfaceTexture",
1056+
getCodec());
1057+
if (api != null) {
1058+
channel.setMessageHandler(
1059+
(message, reply) -> {
1060+
Map<String, Object> wrapped = new HashMap<>();
1061+
try {
1062+
api.releaseFlutterSurfaceTexture();
1063+
wrapped.put("result", null);
1064+
} catch (Error | RuntimeException exception) {
1065+
wrapped.put("error", wrapError(exception));
1066+
}
1067+
reply.reply(wrapped);
1068+
});
1069+
} else {
1070+
channel.setMessageHandler(null);
1071+
}
1072+
}
1073+
{
1074+
BasicMessageChannel<Object> channel =
1075+
new BasicMessageChannel<>(
1076+
binaryMessenger, "dev.flutter.pigeon.PreviewHostApi.getResolutionInfo", getCodec());
1077+
if (api != null) {
1078+
channel.setMessageHandler(
1079+
(message, reply) -> {
1080+
Map<String, Object> wrapped = new HashMap<>();
1081+
try {
1082+
ArrayList<Object> args = (ArrayList<Object>) message;
1083+
Number identifierArg = (Number) args.get(0);
1084+
if (identifierArg == null) {
1085+
throw new NullPointerException("identifierArg unexpectedly null.");
1086+
}
1087+
ResolutionInfo output =
1088+
api.getResolutionInfo(
1089+
(identifierArg == null) ? null : identifierArg.longValue());
1090+
wrapped.put("result", output);
1091+
} catch (Error | RuntimeException exception) {
1092+
wrapped.put("error", wrapError(exception));
1093+
}
1094+
reply.reply(wrapped);
1095+
});
1096+
} else {
1097+
channel.setMessageHandler(null);
1098+
}
1099+
}
1100+
}
8461101
}
8471102

8481103
private static Map<String, Object> wrapError(Throwable exception) {

0 commit comments

Comments
 (0)