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

Commit

Permalink
[camerax] Adds functionality to bind UseCases to a lifecycle (#6939)
Browse files Browse the repository at this point in the history
* Copy over code from proof of concept

* Add dart tests

* Fix dart tests

* Add java tests

* Add me as owner and changelog change

* Fix analyzer

* Add instance manager fix

* Update comment

* Undo instance manager changes

* Formatting

* Fix analyze

* Address review

* Fix analyze

* Add import

* Fix assertion error

* Remove unecessary this keywrod

* Update packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java

Co-authored-by: Maurice Parrish <10687576+bparrishMines@users.noreply.github.com>

Co-authored-by: Maurice Parrish <10687576+bparrishMines@users.noreply.github.com>
  • Loading branch information
camsim99 and bparrishMines committed Jan 25, 2023
1 parent dc8ad77 commit e9406bc
Show file tree
Hide file tree
Showing 22 changed files with 945 additions and 44 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
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
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.
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
@@ -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);
}
}
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());
}
}
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
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

0 comments on commit e9406bc

Please sign in to comment.