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

[camerax] Adds functionality to bind UseCases to a lifecycle #6939

Merged
merged 18 commits into from
Jan 25, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ packages/**/*_web/** @ditman

# - Android
packages/camera/camera_android/** @camsim99
packages/camera/camera_android_camerax/** @camsim99
packages/espresso/** @GaryQian
packages/flutter_plugin_android_lifecycle/** @GaryQian
packages/google_maps_flutter/google_maps_flutter_android/** @GaryQian
Expand Down
1 change: 1 addition & 0 deletions packages/camera/camera_android_camerax/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
* Adds CameraSelector class.
* Adds ProcessCameraProvider class.
* Bump CameraX version to 1.3.0-alpha02.
* Adds Camera and UseCase classes, along with methods for binding UseCases to a lifecycle with the ProcessCameraProvider.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import android.content.Context;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
Expand All @@ -15,7 +16,7 @@
public final class CameraAndroidCameraxPlugin implements FlutterPlugin, ActivityAware {
private InstanceManager instanceManager;
private FlutterPluginBinding pluginBinding;
private ProcessCameraProviderHostApiImpl processCameraProviderHostApi;
public ProcessCameraProviderHostApiImpl processCameraProviderHostApi;

/**
* Initialize this within the {@code #configureFlutterEngine} of a Flutter activity or fragment.
Expand All @@ -36,10 +37,10 @@ void setUp(BinaryMessenger binaryMessenger, Context context) {
// Set up Host APIs.
GeneratedCameraXLibrary.CameraInfoHostApi.setup(
binaryMessenger, new CameraInfoHostApiImpl(instanceManager));
GeneratedCameraXLibrary.JavaObjectHostApi.setup(
binaryMessenger, new JavaObjectHostApiImpl(instanceManager));
GeneratedCameraXLibrary.CameraSelectorHostApi.setup(
binaryMessenger, new CameraSelectorHostApiImpl(binaryMessenger, instanceManager));
GeneratedCameraXLibrary.JavaObjectHostApi.setup(
binaryMessenger, new JavaObjectHostApiImpl(instanceManager));
processCameraProviderHostApi =
new ProcessCameraProviderHostApiImpl(binaryMessenger, instanceManager, context);
GeneratedCameraXLibrary.ProcessCameraProviderHostApi.setup(
Expand All @@ -49,10 +50,6 @@ void setUp(BinaryMessenger binaryMessenger, Context context) {
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
pluginBinding = flutterPluginBinding;
(new CameraAndroidCameraxPlugin())
.setUp(
flutterPluginBinding.getBinaryMessenger(),
flutterPluginBinding.getApplicationContext());
}

@Override
Expand All @@ -66,7 +63,10 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {

@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) {
updateContext(activityPluginBinding.getActivity());
setUp(pluginBinding.getBinaryMessenger(), pluginBinding.getApplicationContext());
updateContext(pluginBinding.getApplicationContext());
processCameraProviderHostApi.setLifecycleOwner(
(LifecycleOwner) activityPluginBinding.getActivity());
}

@Override
Expand All @@ -89,7 +89,7 @@ public void onDetachedFromActivity() {
* Updates context that is used to fetch the corresponding instance of a {@code
* ProcessCameraProvider}.
*/
private void updateContext(Context context) {
public void updateContext(Context context) {
if (processCameraProviderHostApi != null) {
processCameraProviderHostApi.setContext(context);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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.

package io.flutter.plugins.camerax;

import androidx.camera.core.Camera;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraFlutterApi;

public class CameraFlutterApiImpl extends CameraFlutterApi {
private final InstanceManager instanceManager;

public CameraFlutterApiImpl(BinaryMessenger binaryMessenger, InstanceManager instanceManager) {
super(binaryMessenger);
this.instanceManager = instanceManager;
}

void create(Camera camera, Reply<Void> reply) {
create(instanceManager.addHostCreatedInstance(camera), reply);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import androidx.annotation.NonNull;
import androidx.camera.core.CameraInfo;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraInfoHostApi;
import java.util.Objects;

public class CameraInfoHostApiImpl implements CameraInfoHostApi {
private final InstanceManager instanceManager;
Expand All @@ -17,7 +18,8 @@ public CameraInfoHostApiImpl(InstanceManager instanceManager) {

@Override
public Long getSensorRotationDegrees(@NonNull Long identifier) {
CameraInfo cameraInfo = (CameraInfo) instanceManager.getInstance(identifier);
CameraInfo cameraInfo =
(CameraInfo) Objects.requireNonNull(instanceManager.getInstance(identifier));
return Long.valueOf(cameraInfo.getSensorRotationDegrees());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraSelectorHostApi;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class CameraSelectorHostApiImpl implements CameraSelectorHostApi {
private final BinaryMessenger binaryMessenger;
Expand Down Expand Up @@ -41,13 +42,15 @@ public void create(@NonNull Long identifier, Long lensFacing) {

@Override
public List<Long> filter(@NonNull Long identifier, @NonNull List<Long> cameraInfoIds) {
CameraSelector cameraSelector = (CameraSelector) instanceManager.getInstance(identifier);
CameraSelector cameraSelector =
(CameraSelector) Objects.requireNonNull(instanceManager.getInstance(identifier));
List<CameraInfo> cameraInfosForFilter = new ArrayList<CameraInfo>();

for (Number cameraInfoAsNumber : cameraInfoIds) {
Long cameraInfoId = cameraInfoAsNumber.longValue();

CameraInfo cameraInfo = (CameraInfo) instanceManager.getInstance(cameraInfoId);
CameraInfo cameraInfo =
(CameraInfo) Objects.requireNonNull(instanceManager.getInstance(cameraInfoId));
cameraInfosForFilter.add(cameraInfo);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,16 @@ public interface ProcessCameraProviderHostApi {
@NonNull
List<Long> getAvailableCameraInfos(@NonNull Long identifier);

@NonNull
Long bindToLifecycle(
@NonNull Long identifier,
@NonNull Long cameraSelectorIdentifier,
@NonNull List<Long> useCaseIds);

void unbind(@NonNull Long identifier, @NonNull List<Long> useCaseIds);

void unbindAll(@NonNull Long identifier);

/** The codec used by ProcessCameraProviderHostApi. */
static MessageCodec<Object> getCodec() {
return ProcessCameraProviderHostApiCodec.INSTANCE;
Expand Down Expand Up @@ -405,6 +415,107 @@ public void error(Throwable error) {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.ProcessCameraProviderHostApi.bindToLifecycle",
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
Number identifierArg = (Number) args.get(0);
if (identifierArg == null) {
throw new NullPointerException("identifierArg unexpectedly null.");
}
Number cameraSelectorIdentifierArg = (Number) args.get(1);
if (cameraSelectorIdentifierArg == null) {
throw new NullPointerException(
"cameraSelectorIdentifierArg unexpectedly null.");
}
List<Long> useCaseIdsArg = (List<Long>) args.get(2);
if (useCaseIdsArg == null) {
throw new NullPointerException("useCaseIdsArg unexpectedly null.");
}
Long output =
api.bindToLifecycle(
(identifierArg == null) ? null : identifierArg.longValue(),
(cameraSelectorIdentifierArg == null)
? null
: cameraSelectorIdentifierArg.longValue(),
useCaseIdsArg);
wrapped.put("result", output);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.ProcessCameraProviderHostApi.unbind",
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
Number identifierArg = (Number) args.get(0);
if (identifierArg == null) {
throw new NullPointerException("identifierArg unexpectedly null.");
}
List<Long> useCaseIdsArg = (List<Long>) args.get(1);
if (useCaseIdsArg == null) {
throw new NullPointerException("useCaseIdsArg unexpectedly null.");
}
api.unbind(
(identifierArg == null) ? null : identifierArg.longValue(), useCaseIdsArg);
wrapped.put("result", null);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.ProcessCameraProviderHostApi.unbindAll",
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
Number identifierArg = (Number) args.get(0);
if (identifierArg == null) {
throw new NullPointerException("identifierArg unexpectedly null.");
}
api.unbindAll((identifierArg == null) ? null : identifierArg.longValue());
wrapped.put("result", null);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}

Expand Down Expand Up @@ -445,6 +556,40 @@ public void create(@NonNull Long identifierArg, Reply<Void> callback) {
}
}

private static class CameraFlutterApiCodec extends StandardMessageCodec {
public static final CameraFlutterApiCodec INSTANCE = new CameraFlutterApiCodec();

private CameraFlutterApiCodec() {}
}

/** Generated class from Pigeon that represents Flutter messages that can be called from Java. */
public static class CameraFlutterApi {
private final BinaryMessenger binaryMessenger;

public CameraFlutterApi(BinaryMessenger argBinaryMessenger) {
this.binaryMessenger = argBinaryMessenger;
}

public interface Reply<T> {
void reply(T reply);
}

static MessageCodec<Object> getCodec() {
return CameraFlutterApiCodec.INSTANCE;
}

public void create(@NonNull Long identifierArg, Reply<Void> callback) {
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.CameraFlutterApi.create", getCodec());
channel.send(
new ArrayList<Object>(Arrays.asList(identifierArg)),
channelReply -> {
callback.reply(null);
});
}
}

private static Map<String, Object> wrapError(Throwable exception) {
Map<String, Object> errorMap = new HashMap<>();
errorMap.put("message", exception.toString());
Expand Down
Loading