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

* 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>
diff --git a/CODEOWNERS b/CODEOWNERS
index f128098..8a46d52 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -28,6 +28,7 @@
 
 # - 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
diff --git a/packages/camera/camera_android_camerax/CHANGELOG.md b/packages/camera/camera_android_camerax/CHANGELOG.md
index f94a860..389fc31 100644
--- a/packages/camera/camera_android_camerax/CHANGELOG.md
+++ b/packages/camera/camera_android_camerax/CHANGELOG.md
@@ -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.
diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java
index b8fbaf5..7ee7263 100644
--- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java
+++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java
@@ -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;
@@ -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.
@@ -36,10 +37,10 @@
     // 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(
@@ -49,10 +50,6 @@
   @Override
   public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
     pluginBinding = flutterPluginBinding;
-    (new CameraAndroidCameraxPlugin())
-        .setUp(
-            flutterPluginBinding.getBinaryMessenger(),
-            flutterPluginBinding.getApplicationContext());
   }
 
   @Override
@@ -66,7 +63,10 @@
 
   @Override
   public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) {
-    updateContext(activityPluginBinding.getActivity());
+    setUp(pluginBinding.getBinaryMessenger(), pluginBinding.getApplicationContext());
+    updateContext(pluginBinding.getApplicationContext());
+    processCameraProviderHostApi.setLifecycleOwner(
+        (LifecycleOwner) activityPluginBinding.getActivity());
   }
 
   @Override
@@ -89,7 +89,7 @@
    * 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);
     }
diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraFlutterApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraFlutterApiImpl.java
new file mode 100644
index 0000000..a035483
--- /dev/null
+++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraFlutterApiImpl.java
@@ -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);
+  }
+}
diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoHostApiImpl.java
index 7daba0d..d960b7f 100644
--- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoHostApiImpl.java
+++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoHostApiImpl.java
@@ -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;
@@ -17,7 +18,8 @@
 
   @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());
   }
 }
diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraSelectorHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraSelectorHostApiImpl.java
index 9c559a7..87c69de 100644
--- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraSelectorHostApiImpl.java
+++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraSelectorHostApiImpl.java
@@ -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;
@@ -41,13 +42,15 @@
 
   @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);
     }
 
diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java
index 041564c..8c42a79 100644
--- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java
+++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java
@@ -332,6 +332,16 @@
     @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;
@@ -405,6 +415,107 @@
           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);
+        }
+      }
     }
   }
 
@@ -445,6 +556,40 @@
     }
   }
 
+  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());
diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java
index 19c5eb5..f82f18f 100644
--- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java
+++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java
@@ -6,20 +6,26 @@
 
 import android.content.Context;
 import androidx.annotation.NonNull;
+import androidx.camera.core.Camera;
 import androidx.camera.core.CameraInfo;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.UseCase;
 import androidx.camera.lifecycle.ProcessCameraProvider;
 import androidx.core.content.ContextCompat;
+import androidx.lifecycle.LifecycleOwner;
 import com.google.common.util.concurrent.ListenableFuture;
 import io.flutter.plugin.common.BinaryMessenger;
 import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ProcessCameraProviderHostApi;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 public class ProcessCameraProviderHostApiImpl implements ProcessCameraProviderHostApi {
   private final BinaryMessenger binaryMessenger;
   private final InstanceManager instanceManager;
 
   private Context context;
+  private LifecycleOwner lifecycleOwner;
 
   public ProcessCameraProviderHostApiImpl(
       BinaryMessenger binaryMessenger, InstanceManager instanceManager, Context context) {
@@ -28,6 +34,10 @@
     this.context = context;
   }
 
+  public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
+    this.lifecycleOwner = lifecycleOwner;
+  }
+
   /**
    * Sets the context that the {@code ProcessCameraProvider} will use to attach the lifecycle of the
    * camera to.
@@ -40,8 +50,8 @@
   }
 
   /**
-   * Returns the instance of the ProcessCameraProvider to manage the lifecycle of the camera for the
-   * current {@code Context}.
+   * Returns the instance of the {@code ProcessCameraProvider} to manage the lifecycle of the camera
+   * for the current {@code Context}.
    */
   @Override
   public void getInstance(GeneratedCameraXLibrary.Result<Long> result) {
@@ -54,11 +64,9 @@
             // Camera provider is now guaranteed to be available.
             ProcessCameraProvider processCameraProvider = processCameraProviderFuture.get();
 
-            if (!instanceManager.containsInstance(processCameraProvider)) {
-              final ProcessCameraProviderFlutterApiImpl flutterApi =
-                  new ProcessCameraProviderFlutterApiImpl(binaryMessenger, instanceManager);
-              flutterApi.create(processCameraProvider, reply -> {});
-            }
+            final ProcessCameraProviderFlutterApiImpl flutterApi =
+                new ProcessCameraProviderFlutterApiImpl(binaryMessenger, instanceManager);
+            flutterApi.create(processCameraProvider, reply -> {});
             result.success(instanceManager.getIdentifierForStrongReference(processCameraProvider));
           } catch (Exception e) {
             result.error(e);
@@ -67,11 +75,11 @@
         ContextCompat.getMainExecutor(context));
   }
 
-  /** Returns cameras available to the ProcessCameraProvider. */
+  /** Returns cameras available to the {@code ProcessCameraProvider}. */
   @Override
   public List<Long> getAvailableCameraInfos(@NonNull Long identifier) {
     ProcessCameraProvider processCameraProvider =
-        (ProcessCameraProvider) instanceManager.getInstance(identifier);
+        (ProcessCameraProvider) Objects.requireNonNull(instanceManager.getInstance(identifier));
 
     List<CameraInfo> availableCameras = processCameraProvider.getAvailableCameraInfos();
     List<Long> availableCamerasIds = new ArrayList<Long>();
@@ -84,4 +92,59 @@
     }
     return availableCamerasIds;
   }
+
+  /**
+   * Binds specified {@code UseCase}s to the lifecycle of the {@code LifecycleOwner} that
+   * corresponds to this instance and returns the instance of the {@code Camera} whose lifecycle
+   * that {@code LifecycleOwner} reflects.
+   */
+  @Override
+  public Long bindToLifecycle(
+      @NonNull Long identifier,
+      @NonNull Long cameraSelectorIdentifier,
+      @NonNull List<Long> useCaseIds) {
+    ProcessCameraProvider processCameraProvider =
+        (ProcessCameraProvider) Objects.requireNonNull(instanceManager.getInstance(identifier));
+    CameraSelector cameraSelector =
+        (CameraSelector)
+            Objects.requireNonNull(instanceManager.getInstance(cameraSelectorIdentifier));
+    UseCase[] useCases = new UseCase[useCaseIds.size()];
+    for (int i = 0; i < useCaseIds.size(); i++) {
+      useCases[i] =
+          (UseCase)
+              Objects.requireNonNull(
+                  instanceManager.getInstance(((Number) useCaseIds.get(i)).longValue()));
+    }
+
+    Camera camera =
+        processCameraProvider.bindToLifecycle(
+            (LifecycleOwner) lifecycleOwner, cameraSelector, useCases);
+
+    final CameraFlutterApiImpl cameraFlutterApi =
+        new CameraFlutterApiImpl(binaryMessenger, instanceManager);
+    cameraFlutterApi.create(camera, result -> {});
+
+    return instanceManager.getIdentifierForStrongReference(camera);
+  }
+
+  @Override
+  public void unbind(@NonNull Long identifier, @NonNull List<Long> useCaseIds) {
+    ProcessCameraProvider processCameraProvider =
+        (ProcessCameraProvider) Objects.requireNonNull(instanceManager.getInstance(identifier));
+    UseCase[] useCases = new UseCase[useCaseIds.size()];
+    for (int i = 0; i < useCaseIds.size(); i++) {
+      useCases[i] =
+          (UseCase)
+              Objects.requireNonNull(
+                  instanceManager.getInstance(((Number) useCaseIds.get(i)).longValue()));
+    }
+    processCameraProvider.unbind(useCases);
+  }
+
+  @Override
+  public void unbindAll(@NonNull Long identifier) {
+    ProcessCameraProvider processCameraProvider =
+        (ProcessCameraProvider) Objects.requireNonNull(instanceManager.getInstance(identifier));
+    processCameraProvider.unbindAll();
+  }
 }
diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraTest.java
new file mode 100644
index 0000000..e2135b3
--- /dev/null
+++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraTest.java
@@ -0,0 +1,52 @@
+// 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 static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import androidx.camera.core.Camera;
+import io.flutter.plugin.common.BinaryMessenger;
+import java.util.Objects;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+public class CameraTest {
+  @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+  @Mock public BinaryMessenger mockBinaryMessenger;
+  @Mock public Camera camera;
+
+  InstanceManager testInstanceManager;
+
+  @Before
+  public void setUp() {
+    testInstanceManager = InstanceManager.open(identifier -> {});
+  }
+
+  @After
+  public void tearDown() {
+    testInstanceManager.close();
+  }
+
+  @Test
+  public void flutterApiCreateTest() {
+    final CameraFlutterApiImpl spyFlutterApi =
+        spy(new CameraFlutterApiImpl(mockBinaryMessenger, testInstanceManager));
+
+    spyFlutterApi.create(camera, reply -> {});
+
+    final long identifier =
+        Objects.requireNonNull(testInstanceManager.getIdentifierForStrongReference(camera));
+    verify(spyFlutterApi).create(eq(identifier), any());
+  }
+}
diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ProcessCameraProviderTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ProcessCameraProviderTest.java
index 5008e4e..47b4ed6 100644
--- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ProcessCameraProviderTest.java
+++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ProcessCameraProviderTest.java
@@ -13,8 +13,12 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import androidx.camera.core.Camera;
 import androidx.camera.core.CameraInfo;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.UseCase;
 import androidx.camera.lifecycle.ProcessCameraProvider;
+import androidx.lifecycle.LifecycleOwner;
 import androidx.test.core.app.ApplicationProvider;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -100,6 +104,58 @@
   }
 
   @Test
+  public void bindToLifecycleTest() {
+    final ProcessCameraProviderHostApiImpl processCameraProviderHostApi =
+        new ProcessCameraProviderHostApiImpl(mockBinaryMessenger, testInstanceManager, context);
+    final Camera mockCamera = mock(Camera.class);
+    final CameraSelector mockCameraSelector = mock(CameraSelector.class);
+    final UseCase mockUseCase = mock(UseCase.class);
+    UseCase[] mockUseCases = new UseCase[] {mockUseCase};
+
+    LifecycleOwner mockLifecycleOwner = mock(LifecycleOwner.class);
+    processCameraProviderHostApi.setLifecycleOwner(mockLifecycleOwner);
+
+    testInstanceManager.addDartCreatedInstance(processCameraProvider, 0);
+    testInstanceManager.addDartCreatedInstance(mockCameraSelector, 1);
+    testInstanceManager.addDartCreatedInstance(mockUseCase, 2);
+    testInstanceManager.addDartCreatedInstance(mockCamera, 3);
+
+    when(processCameraProvider.bindToLifecycle(
+            mockLifecycleOwner, mockCameraSelector, mockUseCases))
+        .thenReturn(mockCamera);
+
+    assertEquals(
+        processCameraProviderHostApi.bindToLifecycle(0L, 1L, Arrays.asList(2L)), Long.valueOf(3));
+    verify(processCameraProvider)
+        .bindToLifecycle(mockLifecycleOwner, mockCameraSelector, mockUseCases);
+  }
+
+  @Test
+  public void unbindTest() {
+    final ProcessCameraProviderHostApiImpl processCameraProviderHostApi =
+        new ProcessCameraProviderHostApiImpl(mockBinaryMessenger, testInstanceManager, context);
+    final UseCase mockUseCase = mock(UseCase.class);
+    UseCase[] mockUseCases = new UseCase[] {mockUseCase};
+
+    testInstanceManager.addDartCreatedInstance(processCameraProvider, 0);
+    testInstanceManager.addDartCreatedInstance(mockUseCase, 1);
+
+    processCameraProviderHostApi.unbind(0L, Arrays.asList(1L));
+    verify(processCameraProvider).unbind(mockUseCases);
+  }
+
+  @Test
+  public void unbindAllTest() {
+    final ProcessCameraProviderHostApiImpl processCameraProviderHostApi =
+        new ProcessCameraProviderHostApiImpl(mockBinaryMessenger, testInstanceManager, context);
+
+    testInstanceManager.addDartCreatedInstance(processCameraProvider, 0);
+
+    processCameraProviderHostApi.unbindAll(0L);
+    verify(processCameraProvider).unbindAll();
+  }
+
+  @Test
   public void flutterApiCreateTest() {
     final ProcessCameraProviderFlutterApiImpl spyFlutterApi =
         spy(new ProcessCameraProviderFlutterApiImpl(mockBinaryMessenger, testInstanceManager));
diff --git a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax_flutter_api_impls.dart b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax_flutter_api_impls.dart
index 9c6564a..620831b 100644
--- a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax_flutter_api_impls.dart
+++ b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax_flutter_api_impls.dart
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'camera.dart';
 import 'camera_info.dart';
 import 'camera_selector.dart';
 import 'camerax_library.pigeon.dart';
@@ -13,6 +14,7 @@
   /// Creates a [AndroidCameraXCameraFlutterApis].
   AndroidCameraXCameraFlutterApis({
     JavaObjectFlutterApiImpl? javaObjectFlutterApi,
+    CameraFlutterApiImpl? cameraFlutterApi,
     CameraInfoFlutterApiImpl? cameraInfoFlutterApi,
     CameraSelectorFlutterApiImpl? cameraSelectorFlutterApi,
     ProcessCameraProviderFlutterApiImpl? processCameraProviderFlutterApi,
@@ -25,6 +27,7 @@
         cameraSelectorFlutterApi ?? CameraSelectorFlutterApiImpl();
     this.processCameraProviderFlutterApi = processCameraProviderFlutterApi ??
         ProcessCameraProviderFlutterApiImpl();
+    this.cameraFlutterApi = cameraFlutterApi ?? CameraFlutterApiImpl();
   }
 
   static bool _haveBeenSetUp = false;
@@ -48,6 +51,9 @@
   late final ProcessCameraProviderFlutterApiImpl
       processCameraProviderFlutterApi;
 
+  /// Flutter Api for [Camera].
+  late final CameraFlutterApiImpl cameraFlutterApi;
+
   /// Ensures all the Flutter APIs have been setup to receive calls from native code.
   void ensureSetUp() {
     if (!_haveBeenSetUp) {
@@ -55,6 +61,7 @@
       CameraInfoFlutterApi.setup(cameraInfoFlutterApi);
       CameraSelectorFlutterApi.setup(cameraSelectorFlutterApi);
       ProcessCameraProviderFlutterApi.setup(processCameraProviderFlutterApi);
+      CameraFlutterApi.setup(cameraFlutterApi);
       _haveBeenSetUp = true;
     }
   }
diff --git a/packages/camera/camera_android_camerax/lib/src/camera.dart b/packages/camera/camera_android_camerax/lib/src/camera.dart
new file mode 100644
index 0000000..0a3820c
--- /dev/null
+++ b/packages/camera/camera_android_camerax/lib/src/camera.dart
@@ -0,0 +1,53 @@
+// 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.
+
+import 'package:flutter/services.dart' show BinaryMessenger;
+
+import 'android_camera_camerax_flutter_api_impls.dart';
+import 'camerax_library.pigeon.dart';
+import 'instance_manager.dart';
+import 'java_object.dart';
+
+/// The interface used to control the flow of data of use cases, control the
+/// camera, and publich the state of the camera.
+///
+/// See https://developer.android.com/reference/androidx/camera/core/Camera.
+class Camera extends JavaObject {
+  /// Constructs a [Camera] that is not automatically attached to a native object.
+  Camera.detached({super.binaryMessenger, super.instanceManager})
+      : super.detached() {
+    AndroidCameraXCameraFlutterApis.instance.ensureSetUp();
+  }
+}
+
+/// Flutter API implementation of [Camera].
+class CameraFlutterApiImpl implements CameraFlutterApi {
+  /// Constructs a [CameraSelectorFlutterApiImpl].
+  CameraFlutterApiImpl({
+    this.binaryMessenger,
+    InstanceManager? instanceManager,
+  }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager;
+
+  /// Receives binary data across the Flutter platform barrier.
+  ///
+  /// If it is null, the default BinaryMessenger will be used which routes to
+  /// the host platform.
+  final BinaryMessenger? binaryMessenger;
+
+  /// Maintains instances stored to communicate with native language objects.
+  final InstanceManager instanceManager;
+
+  @override
+  void create(int identifier) {
+    instanceManager.addHostCreatedInstance(
+      Camera.detached(
+          binaryMessenger: binaryMessenger, instanceManager: instanceManager),
+      identifier,
+      onCopy: (Camera original) {
+        return Camera.detached(
+            binaryMessenger: binaryMessenger, instanceManager: instanceManager);
+      },
+    );
+  }
+}
diff --git a/packages/camera/camera_android_camerax/lib/src/camerax_library.pigeon.dart b/packages/camera/camera_android_camerax/lib/src/camerax_library.pigeon.dart
index c0b0523..636a375 100644
--- a/packages/camera/camera_android_camerax/lib/src/camerax_library.pigeon.dart
+++ b/packages/camera/camera_android_camerax/lib/src/camerax_library.pigeon.dart
@@ -338,6 +338,89 @@
       return (replyMap['result'] as List<Object?>?)!.cast<int?>();
     }
   }
+
+  Future<int> bindToLifecycle(int arg_identifier,
+      int arg_cameraSelectorIdentifier, List<int?> arg_useCaseIds) async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.ProcessCameraProviderHostApi.bindToLifecycle',
+        codec,
+        binaryMessenger: _binaryMessenger);
+    final Map<Object?, Object?>? replyMap = await channel.send(<Object?>[
+      arg_identifier,
+      arg_cameraSelectorIdentifier,
+      arg_useCaseIds
+    ]) as Map<Object?, Object?>?;
+    if (replyMap == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+      );
+    } else if (replyMap['error'] != null) {
+      final Map<Object?, Object?> error =
+          (replyMap['error'] as Map<Object?, Object?>?)!;
+      throw PlatformException(
+        code: (error['code'] as String?)!,
+        message: error['message'] as String?,
+        details: error['details'],
+      );
+    } else if (replyMap['result'] == null) {
+      throw PlatformException(
+        code: 'null-error',
+        message: 'Host platform returned null value for non-null return value.',
+      );
+    } else {
+      return (replyMap['result'] as int?)!;
+    }
+  }
+
+  Future<void> unbind(int arg_identifier, List<int?> arg_useCaseIds) async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.ProcessCameraProviderHostApi.unbind', codec,
+        binaryMessenger: _binaryMessenger);
+    final Map<Object?, Object?>? replyMap =
+        await channel.send(<Object?>[arg_identifier, arg_useCaseIds])
+            as Map<Object?, Object?>?;
+    if (replyMap == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+      );
+    } else if (replyMap['error'] != null) {
+      final Map<Object?, Object?> error =
+          (replyMap['error'] as Map<Object?, Object?>?)!;
+      throw PlatformException(
+        code: (error['code'] as String?)!,
+        message: error['message'] as String?,
+        details: error['details'],
+      );
+    } else {
+      return;
+    }
+  }
+
+  Future<void> unbindAll(int arg_identifier) async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.ProcessCameraProviderHostApi.unbindAll', codec,
+        binaryMessenger: _binaryMessenger);
+    final Map<Object?, Object?>? replyMap =
+        await channel.send(<Object?>[arg_identifier]) as Map<Object?, Object?>?;
+    if (replyMap == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+      );
+    } else if (replyMap['error'] != null) {
+      final Map<Object?, Object?> error =
+          (replyMap['error'] as Map<Object?, Object?>?)!;
+      throw PlatformException(
+        code: (error['code'] as String?)!,
+        message: error['message'] as String?,
+        details: error['details'],
+      );
+    } else {
+      return;
+    }
+  }
 }
 
 class _ProcessCameraProviderFlutterApiCodec extends StandardMessageCodec {
@@ -372,3 +455,34 @@
     }
   }
 }
+
+class _CameraFlutterApiCodec extends StandardMessageCodec {
+  const _CameraFlutterApiCodec();
+}
+
+abstract class CameraFlutterApi {
+  static const MessageCodec<Object?> codec = _CameraFlutterApiCodec();
+
+  void create(int identifier);
+  static void setup(CameraFlutterApi? api, {BinaryMessenger? binaryMessenger}) {
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.CameraFlutterApi.create', codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMessageHandler(null);
+      } else {
+        channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.CameraFlutterApi.create was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_identifier = (args[0] as int?);
+          assert(arg_identifier != null,
+              'Argument for dev.flutter.pigeon.CameraFlutterApi.create was null, expected non-null int.');
+          api.create(arg_identifier!);
+          return;
+        });
+      }
+    }
+  }
+}
diff --git a/packages/camera/camera_android_camerax/lib/src/process_camera_provider.dart b/packages/camera/camera_android_camerax/lib/src/process_camera_provider.dart
index 5a67fa7..30c8162 100644
--- a/packages/camera/camera_android_camerax/lib/src/process_camera_provider.dart
+++ b/packages/camera/camera_android_camerax/lib/src/process_camera_provider.dart
@@ -5,10 +5,13 @@
 import 'package:flutter/services.dart';
 
 import 'android_camera_camerax_flutter_api_impls.dart';
+import 'camera.dart';
 import 'camera_info.dart';
+import 'camera_selector.dart';
 import 'camerax_library.pigeon.dart';
 import 'instance_manager.dart';
 import 'java_object.dart';
+import 'use_case.dart';
 
 /// Provides an object to manage the camera.
 ///
@@ -42,6 +45,25 @@
   Future<List<CameraInfo>> getAvailableCameraInfos() {
     return _api.getAvailableCameraInfosFromInstances(this);
   }
+
+  /// Binds the specified [UseCase]s to the lifecycle of the camera that it
+  /// returns.
+  Future<Camera> bindToLifecycle(
+      CameraSelector cameraSelector, List<UseCase> useCases) {
+    return _api.bindToLifecycleFromInstances(this, cameraSelector, useCases);
+  }
+
+  /// Unbinds specified [UseCase]s from the lifecycle of the camera that this
+  /// instance tracks.
+  void unbind(List<UseCase> useCases) {
+    _api.unbindFromInstances(this, useCases);
+  }
+
+  /// Unbinds all previously bound [UseCase]s from the lifecycle of the camera
+  /// that this tracks.
+  void unbindAll() {
+    _api.unbindAllFromInstances(this);
+  }
 }
 
 /// Host API implementation of [ProcessCameraProvider].
@@ -69,22 +91,71 @@
         as ProcessCameraProvider;
   }
 
+  /// Gets identifier that the [instanceManager] has set for
+  /// the [ProcessCameraProvider] instance.
+  int getProcessCameraProviderIdentifier(ProcessCameraProvider instance) {
+    final int? identifier = instanceManager.getIdentifier(instance);
+
+    assert(identifier != null,
+        'No ProcessCameraProvider has the identifer of that which was requested.');
+    return identifier!;
+  }
+
   /// Retrives the list of CameraInfos corresponding to the available cameras.
   Future<List<CameraInfo>> getAvailableCameraInfosFromInstances(
       ProcessCameraProvider instance) async {
-    int? identifier = instanceManager.getIdentifier(instance);
-    identifier ??= instanceManager.addDartCreatedInstance(instance,
-        onCopy: (ProcessCameraProvider original) {
-      return ProcessCameraProvider.detached(
-          binaryMessenger: binaryMessenger, instanceManager: instanceManager);
-    });
-
+    final int identifier = getProcessCameraProviderIdentifier(instance);
     final List<int?> cameraInfos = await getAvailableCameraInfos(identifier);
     return cameraInfos
         .map<CameraInfo>((int? id) =>
             instanceManager.getInstanceWithWeakReference(id!)! as CameraInfo)
         .toList();
   }
+
+  /// Binds the specified [UseCase]s to the lifecycle of the camera which
+  /// the provided [ProcessCameraProvider] instance tracks.
+  ///
+  /// The instance of the camera whose lifecycle the [UseCase]s are bound to
+  /// is returned.
+  Future<Camera> bindToLifecycleFromInstances(
+    ProcessCameraProvider instance,
+    CameraSelector cameraSelector,
+    List<UseCase> useCases,
+  ) async {
+    final int identifier = getProcessCameraProviderIdentifier(instance);
+    final List<int> useCaseIds = useCases
+        .map<int>((UseCase useCase) => instanceManager.getIdentifier(useCase)!)
+        .toList();
+
+    final int cameraIdentifier = await bindToLifecycle(
+      identifier,
+      instanceManager.getIdentifier(cameraSelector)!,
+      useCaseIds,
+    );
+    return instanceManager.getInstanceWithWeakReference(cameraIdentifier)!
+        as Camera;
+  }
+
+  /// Unbinds specified [UseCase]s from the lifecycle of the camera which the
+  /// provided [ProcessCameraProvider] instance tracks.
+  void unbindFromInstances(
+    ProcessCameraProvider instance,
+    List<UseCase> useCases,
+  ) {
+    final int identifier = getProcessCameraProviderIdentifier(instance);
+    final List<int> useCaseIds = useCases
+        .map<int>((UseCase useCase) => instanceManager.getIdentifier(useCase)!)
+        .toList();
+
+    unbind(identifier, useCaseIds);
+  }
+
+  /// Unbinds all previously bound [UseCase]s from the lifecycle of the camera
+  /// which the provided [ProcessCameraProvider] instance tracks.
+  void unbindAllFromInstances(ProcessCameraProvider instance) {
+    final int identifier = getProcessCameraProviderIdentifier(instance);
+    unbindAll(identifier);
+  }
 }
 
 /// Flutter API Implementation of [ProcessCameraProvider].
diff --git a/packages/camera/camera_android_camerax/lib/src/use_case.dart b/packages/camera/camera_android_camerax/lib/src/use_case.dart
new file mode 100644
index 0000000..f8910d9
--- /dev/null
+++ b/packages/camera/camera_android_camerax/lib/src/use_case.dart
@@ -0,0 +1,14 @@
+// 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.
+
+import 'java_object.dart';
+
+/// An object representing the different functionalitites of the camera.
+///
+/// See https://developer.android.com/reference/androidx/camera/core/UseCase.
+class UseCase extends JavaObject {
+  /// Creates a detached [UseCase].
+  UseCase.detached({super.binaryMessenger, super.instanceManager})
+      : super.detached();
+}
diff --git a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart
index 4d7d969..edd2059 100644
--- a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart
+++ b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart
@@ -64,9 +64,21 @@
   int getInstance();
 
   List<int> getAvailableCameraInfos(int identifier);
+
+  int bindToLifecycle(
+      int identifier, int cameraSelectorIdentifier, List<int> useCaseIds);
+
+  void unbind(int identifier, List<int> useCaseIds);
+
+  void unbindAll(int identifier);
 }
 
 @FlutterApi()
 abstract class ProcessCameraProviderFlutterApi {
   void create(int identifier);
 }
+
+@FlutterApi()
+abstract class CameraFlutterApi {
+  void create(int identifier);
+}
diff --git a/packages/camera/camera_android_camerax/test/camera_info_test.mocks.dart b/packages/camera/camera_android_camerax/test/camera_info_test.mocks.dart
index e1f1e3c..63ec03c 100644
--- a/packages/camera/camera_android_camerax/test/camera_info_test.mocks.dart
+++ b/packages/camera/camera_android_camerax/test/camera_info_test.mocks.dart
@@ -1,4 +1,4 @@
-// Mocks generated by Mockito 5.3.0 from annotations
+// Mocks generated by Mockito 5.3.2 from annotations
 // in camera_android_camerax/test/camera_info_test.dart.
 // Do not manually edit this file.
 
@@ -29,6 +29,10 @@
 
   @override
   int getSensorRotationDegrees(int? identifier) => (super.noSuchMethod(
-      Invocation.method(#getSensorRotationDegrees, [identifier]),
-      returnValue: 0) as int);
+        Invocation.method(
+          #getSensorRotationDegrees,
+          [identifier],
+        ),
+        returnValue: 0,
+      ) as int);
 }
diff --git a/packages/camera/camera_android_camerax/test/camera_selector_test.mocks.dart b/packages/camera/camera_android_camerax/test/camera_selector_test.mocks.dart
index 456db1e..bb08c82 100644
--- a/packages/camera/camera_android_camerax/test/camera_selector_test.mocks.dart
+++ b/packages/camera/camera_android_camerax/test/camera_selector_test.mocks.dart
@@ -1,4 +1,4 @@
-// Mocks generated by Mockito 5.3.0 from annotations
+// Mocks generated by Mockito 5.3.2 from annotations
 // in camera_android_camerax/test/camera_selector_test.dart.
 // Do not manually edit this file.
 
@@ -28,11 +28,33 @@
   }
 
   @override
-  void create(int? identifier, int? lensFacing) =>
-      super.noSuchMethod(Invocation.method(#create, [identifier, lensFacing]),
-          returnValueForMissingStub: null);
+  void create(
+    int? identifier,
+    int? lensFacing,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #create,
+          [
+            identifier,
+            lensFacing,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
   @override
-  List<int?> filter(int? identifier, List<int?>? cameraInfoIds) => (super
-      .noSuchMethod(Invocation.method(#filter, [identifier, cameraInfoIds]),
-          returnValue: <int?>[]) as List<int?>);
+  List<int?> filter(
+    int? identifier,
+    List<int?>? cameraInfoIds,
+  ) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #filter,
+          [
+            identifier,
+            cameraInfoIds,
+          ],
+        ),
+        returnValue: <int?>[],
+      ) as List<int?>);
 }
diff --git a/packages/camera/camera_android_camerax/test/camera_test.dart b/packages/camera/camera_android_camerax/test/camera_test.dart
new file mode 100644
index 0000000..c294828
--- /dev/null
+++ b/packages/camera/camera_android_camerax/test/camera_test.dart
@@ -0,0 +1,26 @@
+// 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.
+
+import 'package:camera_android_camerax/src/camera.dart';
+import 'package:camera_android_camerax/src/instance_manager.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+  TestWidgetsFlutterBinding.ensureInitialized();
+
+  group('Camera', () {
+    test('flutterApiCreateTest', () {
+      final InstanceManager instanceManager = InstanceManager(
+        onWeakReferenceRemoved: (_) {},
+      );
+      final CameraFlutterApiImpl flutterApi = CameraFlutterApiImpl(
+        instanceManager: instanceManager,
+      );
+
+      flutterApi.create(0);
+
+      expect(instanceManager.getInstanceWithWeakReference(0), isA<Camera>());
+    });
+  });
+}
diff --git a/packages/camera/camera_android_camerax/test/process_camera_provider_test.dart b/packages/camera/camera_android_camerax/test/process_camera_provider_test.dart
index 65e7d00..c4f56f6 100644
--- a/packages/camera/camera_android_camerax/test/process_camera_provider_test.dart
+++ b/packages/camera/camera_android_camerax/test/process_camera_provider_test.dart
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'package:camera_android_camerax/src/camera.dart';
 import 'package:camera_android_camerax/src/camera_info.dart';
+import 'package:camera_android_camerax/src/camera_selector.dart';
 import 'package:camera_android_camerax/src/instance_manager.dart';
 import 'package:camera_android_camerax/src/process_camera_provider.dart';
+import 'package:camera_android_camerax/src/use_case.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:mockito/annotations.dart';
 import 'package:mockito/mockito.dart';
@@ -78,6 +81,114 @@
       verify(mockApi.getAvailableCameraInfos(0));
     });
 
+    test('bindToLifecycleTest', () async {
+      final MockTestProcessCameraProviderHostApi mockApi =
+          MockTestProcessCameraProviderHostApi();
+      TestProcessCameraProviderHostApi.setup(mockApi);
+
+      final InstanceManager instanceManager = InstanceManager(
+        onWeakReferenceRemoved: (_) {},
+      );
+      final ProcessCameraProvider processCameraProvider =
+          ProcessCameraProvider.detached(
+        instanceManager: instanceManager,
+      );
+      final CameraSelector fakeCameraSelector =
+          CameraSelector.detached(instanceManager: instanceManager);
+      final UseCase fakeUseCase =
+          UseCase.detached(instanceManager: instanceManager);
+      final Camera fakeCamera =
+          Camera.detached(instanceManager: instanceManager);
+
+      instanceManager.addHostCreatedInstance(
+        processCameraProvider,
+        0,
+        onCopy: (_) => ProcessCameraProvider.detached(),
+      );
+      instanceManager.addHostCreatedInstance(
+        fakeCameraSelector,
+        1,
+        onCopy: (_) => CameraSelector.detached(),
+      );
+      instanceManager.addHostCreatedInstance(
+        fakeUseCase,
+        2,
+        onCopy: (_) => UseCase.detached(),
+      );
+      instanceManager.addHostCreatedInstance(
+        fakeCamera,
+        3,
+        onCopy: (_) => Camera.detached(),
+      );
+
+      when(mockApi.bindToLifecycle(0, 1, <int>[2])).thenReturn(3);
+      expect(
+          await processCameraProvider
+              .bindToLifecycle(fakeCameraSelector, <UseCase>[fakeUseCase]),
+          equals(fakeCamera));
+      verify(mockApi.bindToLifecycle(0, 1, <int>[2]));
+    });
+
+    test('unbindTest', () async {
+      final MockTestProcessCameraProviderHostApi mockApi =
+          MockTestProcessCameraProviderHostApi();
+      TestProcessCameraProviderHostApi.setup(mockApi);
+
+      final InstanceManager instanceManager = InstanceManager(
+        onWeakReferenceRemoved: (_) {},
+      );
+      final ProcessCameraProvider processCameraProvider =
+          ProcessCameraProvider.detached(
+        instanceManager: instanceManager,
+      );
+      final UseCase fakeUseCase =
+          UseCase.detached(instanceManager: instanceManager);
+
+      instanceManager.addHostCreatedInstance(
+        processCameraProvider,
+        0,
+        onCopy: (_) => ProcessCameraProvider.detached(),
+      );
+      instanceManager.addHostCreatedInstance(
+        fakeUseCase,
+        1,
+        onCopy: (_) => UseCase.detached(),
+      );
+
+      processCameraProvider.unbind(<UseCase>[fakeUseCase]);
+      verify(mockApi.unbind(0, <int>[1]));
+    });
+
+    test('unbindAllTest', () async {
+      final MockTestProcessCameraProviderHostApi mockApi =
+          MockTestProcessCameraProviderHostApi();
+      TestProcessCameraProviderHostApi.setup(mockApi);
+
+      final InstanceManager instanceManager = InstanceManager(
+        onWeakReferenceRemoved: (_) {},
+      );
+      final ProcessCameraProvider processCameraProvider =
+          ProcessCameraProvider.detached(
+        instanceManager: instanceManager,
+      );
+      final UseCase fakeUseCase =
+          UseCase.detached(instanceManager: instanceManager);
+
+      instanceManager.addHostCreatedInstance(
+        processCameraProvider,
+        0,
+        onCopy: (_) => ProcessCameraProvider.detached(),
+      );
+      instanceManager.addHostCreatedInstance(
+        fakeUseCase,
+        1,
+        onCopy: (_) => UseCase.detached(),
+      );
+
+      processCameraProvider.unbind(<UseCase>[fakeUseCase]);
+      verify(mockApi.unbind(0, <int>[1]));
+    });
+
     test('flutterApiCreateTest', () {
       final InstanceManager instanceManager = InstanceManager(
         onWeakReferenceRemoved: (_) {},
diff --git a/packages/camera/camera_android_camerax/test/process_camera_provider_test.mocks.dart b/packages/camera/camera_android_camerax/test/process_camera_provider_test.mocks.dart
index 9fcfe69..7b0ca76 100644
--- a/packages/camera/camera_android_camerax/test/process_camera_provider_test.mocks.dart
+++ b/packages/camera/camera_android_camerax/test/process_camera_provider_test.mocks.dart
@@ -1,4 +1,4 @@
-// Mocks generated by Mockito 5.3.0 from annotations
+// Mocks generated by Mockito 5.3.2 from annotations
 // in camera_android_camerax/test/process_camera_provider_test.dart.
 // Do not manually edit this file.
 
@@ -30,11 +30,59 @@
   }
 
   @override
-  _i3.Future<int> getInstance() =>
-      (super.noSuchMethod(Invocation.method(#getInstance, []),
-          returnValue: _i3.Future<int>.value(0)) as _i3.Future<int>);
+  _i3.Future<int> getInstance() => (super.noSuchMethod(
+        Invocation.method(
+          #getInstance,
+          [],
+        ),
+        returnValue: _i3.Future<int>.value(0),
+      ) as _i3.Future<int>);
   @override
   List<int?> getAvailableCameraInfos(int? identifier) => (super.noSuchMethod(
-      Invocation.method(#getAvailableCameraInfos, [identifier]),
-      returnValue: <int?>[]) as List<int?>);
+        Invocation.method(
+          #getAvailableCameraInfos,
+          [identifier],
+        ),
+        returnValue: <int?>[],
+      ) as List<int?>);
+  @override
+  int bindToLifecycle(
+    int? identifier,
+    int? cameraSelectorIdentifier,
+    List<int?>? useCaseIds,
+  ) =>
+      (super.noSuchMethod(
+        Invocation.method(
+          #bindToLifecycle,
+          [
+            identifier,
+            cameraSelectorIdentifier,
+            useCaseIds,
+          ],
+        ),
+        returnValue: 0,
+      ) as int);
+  @override
+  void unbind(
+    int? identifier,
+    List<int?>? useCaseIds,
+  ) =>
+      super.noSuchMethod(
+        Invocation.method(
+          #unbind,
+          [
+            identifier,
+            useCaseIds,
+          ],
+        ),
+        returnValueForMissingStub: null,
+      );
+  @override
+  void unbindAll(int? identifier) => super.noSuchMethod(
+        Invocation.method(
+          #unbindAll,
+          [identifier],
+        ),
+        returnValueForMissingStub: null,
+      );
 }
diff --git a/packages/camera/camera_android_camerax/test/test_camerax_library.pigeon.dart b/packages/camera/camera_android_camerax/test/test_camerax_library.pigeon.dart
index 2196b73..c6afe06 100644
--- a/packages/camera/camera_android_camerax/test/test_camerax_library.pigeon.dart
+++ b/packages/camera/camera_android_camerax/test/test_camerax_library.pigeon.dart
@@ -146,6 +146,10 @@
 
   Future<int> getInstance();
   List<int?> getAvailableCameraInfos(int identifier);
+  int bindToLifecycle(
+      int identifier, int cameraSelectorIdentifier, List<int?> useCaseIds);
+  void unbind(int identifier, List<int?> useCaseIds);
+  void unbindAll(int identifier);
   static void setup(TestProcessCameraProviderHostApi? api,
       {BinaryMessenger? binaryMessenger}) {
     {
@@ -183,5 +187,75 @@
         });
       }
     }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.ProcessCameraProviderHostApi.bindToLifecycle',
+          codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.ProcessCameraProviderHostApi.bindToLifecycle was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_identifier = (args[0] as int?);
+          assert(arg_identifier != null,
+              'Argument for dev.flutter.pigeon.ProcessCameraProviderHostApi.bindToLifecycle was null, expected non-null int.');
+          final int? arg_cameraSelectorIdentifier = (args[1] as int?);
+          assert(arg_cameraSelectorIdentifier != null,
+              'Argument for dev.flutter.pigeon.ProcessCameraProviderHostApi.bindToLifecycle was null, expected non-null int.');
+          final List<int?>? arg_useCaseIds =
+              (args[2] as List<Object?>?)?.cast<int?>();
+          assert(arg_useCaseIds != null,
+              'Argument for dev.flutter.pigeon.ProcessCameraProviderHostApi.bindToLifecycle was null, expected non-null List<int?>.');
+          final int output = api.bindToLifecycle(
+              arg_identifier!, arg_cameraSelectorIdentifier!, arg_useCaseIds!);
+          return <Object?, Object?>{'result': output};
+        });
+      }
+    }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.ProcessCameraProviderHostApi.unbind', codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.ProcessCameraProviderHostApi.unbind was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_identifier = (args[0] as int?);
+          assert(arg_identifier != null,
+              'Argument for dev.flutter.pigeon.ProcessCameraProviderHostApi.unbind was null, expected non-null int.');
+          final List<int?>? arg_useCaseIds =
+              (args[1] as List<Object?>?)?.cast<int?>();
+          assert(arg_useCaseIds != null,
+              'Argument for dev.flutter.pigeon.ProcessCameraProviderHostApi.unbind was null, expected non-null List<int?>.');
+          api.unbind(arg_identifier!, arg_useCaseIds!);
+          return <Object?, Object?>{};
+        });
+      }
+    }
+    {
+      final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+          'dev.flutter.pigeon.ProcessCameraProviderHostApi.unbindAll', codec,
+          binaryMessenger: binaryMessenger);
+      if (api == null) {
+        channel.setMockMessageHandler(null);
+      } else {
+        channel.setMockMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.ProcessCameraProviderHostApi.unbindAll was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_identifier = (args[0] as int?);
+          assert(arg_identifier != null,
+              'Argument for dev.flutter.pigeon.ProcessCameraProviderHostApi.unbindAll was null, expected non-null int.');
+          api.unbindAll(arg_identifier!);
+          return <Object?, Object?>{};
+        });
+      }
+    }
   }
 }