Promote UseCaseGroup API out of experimental (Step 1)

Promote UseCaseGroup API for core, lifecycle and video. View artifact's is one version behind. We will have to wait until the next cycle to update the view artifcat.

Also changed:
- In ProcessCameraProvider.java, hide the internal public API. It was created for working around a previous limitation that only one annotation is allowed per method.
- In CameraXActivity.java, merge methods. The additional method was created for working around a previous limitation that only one annotation is allowed per method.

Step 2: In the next release, promote camera-view APIs.
Step 3: In the +2 release, remove the annotations from core and lifecycle.

Relnote: promote the experimental UseCaseGroup API for camera-core, camera-lifecycle and camera-video. Added ViewPort#getLayoutDirection, ViewPort.Builder#setLayoutDirection and ViewPort.Builder#setScaleType for customizing viewport.

Bug: 185869869
Test: manual test and ./gradlew bOS
Change-Id: I7cee86237511def4bbcd0aab8e32a9592ec78dc3
diff --git a/camera/camera-core/api/current.txt b/camera/camera-core/api/current.txt
index 46c69c1..9bceab6 100644
--- a/camera/camera-core/api/current.txt
+++ b/camera/camera-core/api/current.txt
@@ -303,6 +303,7 @@
     method public int getTargetRotation();
     method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
     method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
+    method public void setTargetRotation(int);
   }
 
   public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
@@ -325,8 +326,10 @@
 
   public final class SurfaceRequest {
     method public void addRequestCancellationListener(java.util.concurrent.Executor, Runnable);
+    method public void clearTransformationInfoListener();
     method public android.util.Size getResolution();
     method public void provideSurface(android.view.Surface, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceRequest.Result!>);
+    method public void setTransformationInfoListener(java.util.concurrent.Executor, androidx.camera.core.SurfaceRequest.TransformationInfoListener);
     method public boolean willNotProvideSurface();
   }
 
@@ -340,6 +343,15 @@
     field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
   }
 
+  @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.TransformationInfo {
+    method public abstract android.graphics.Rect getCropRect();
+    method public abstract int getRotationDegrees();
+  }
+
+  public static interface SurfaceRequest.TransformationInfoListener {
+    method public void onTransformationInfoUpdate(androidx.camera.core.SurfaceRequest.TransformationInfo);
+  }
+
   public class TorchState {
     field public static final int OFF = 0; // 0x0
     field public static final int ON = 1; // 0x1
@@ -348,6 +360,36 @@
   public abstract class UseCase {
   }
 
+  public final class UseCaseGroup {
+    method public java.util.List<androidx.camera.core.UseCase!> getUseCases();
+    method public androidx.camera.core.ViewPort? getViewPort();
+  }
+
+  public static final class UseCaseGroup.Builder {
+    ctor public UseCaseGroup.Builder();
+    method public androidx.camera.core.UseCaseGroup.Builder addUseCase(androidx.camera.core.UseCase);
+    method public androidx.camera.core.UseCaseGroup build();
+    method public androidx.camera.core.UseCaseGroup.Builder setViewPort(androidx.camera.core.ViewPort);
+  }
+
+  public final class ViewPort {
+    method public android.util.Rational getAspectRatio();
+    method public int getLayoutDirection();
+    method public int getRotation();
+    method public int getScaleType();
+    field public static final int FILL_CENTER = 1; // 0x1
+    field public static final int FILL_END = 2; // 0x2
+    field public static final int FILL_START = 0; // 0x0
+    field public static final int FIT = 3; // 0x3
+  }
+
+  public static final class ViewPort.Builder {
+    ctor public ViewPort.Builder(android.util.Rational, int);
+    method public androidx.camera.core.ViewPort build();
+    method public androidx.camera.core.ViewPort.Builder setLayoutDirection(int);
+    method public androidx.camera.core.ViewPort.Builder setScaleType(int);
+  }
+
   public interface ZoomState {
     method public float getLinearZoom();
     method public float getMaxZoomRatio();
diff --git a/camera/camera-core/api/public_plus_experimental_current.txt b/camera/camera-core/api/public_plus_experimental_current.txt
index daa3256..9228f3c 100644
--- a/camera/camera-core/api/public_plus_experimental_current.txt
+++ b/camera/camera-core/api/public_plus_experimental_current.txt
@@ -324,7 +324,7 @@
     method public int getTargetRotation();
     method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
     method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
-    method @androidx.camera.core.ExperimentalUseCaseGroup public void setTargetRotation(int);
+    method public void setTargetRotation(int);
   }
 
   public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
@@ -347,10 +347,10 @@
 
   public final class SurfaceRequest {
     method public void addRequestCancellationListener(java.util.concurrent.Executor, Runnable);
-    method @androidx.camera.core.ExperimentalUseCaseGroup public void clearTransformationInfoListener();
+    method public void clearTransformationInfoListener();
     method public android.util.Size getResolution();
     method public void provideSurface(android.view.Surface, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceRequest.Result!>);
-    method @androidx.camera.core.ExperimentalUseCaseGroup public void setTransformationInfoListener(java.util.concurrent.Executor, androidx.camera.core.SurfaceRequest.TransformationInfoListener);
+    method public void setTransformationInfoListener(java.util.concurrent.Executor, androidx.camera.core.SurfaceRequest.TransformationInfoListener);
     method public boolean willNotProvideSurface();
   }
 
@@ -364,12 +364,12 @@
     field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
   }
 
-  @androidx.camera.core.ExperimentalUseCaseGroup @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.TransformationInfo {
+  @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.TransformationInfo {
     method public abstract android.graphics.Rect getCropRect();
     method public abstract int getRotationDegrees();
   }
 
-  @androidx.camera.core.ExperimentalUseCaseGroup public static interface SurfaceRequest.TransformationInfoListener {
+  public static interface SurfaceRequest.TransformationInfoListener {
     method public void onTransformationInfoUpdate(androidx.camera.core.SurfaceRequest.TransformationInfo);
   }
 
@@ -381,20 +381,21 @@
   public abstract class UseCase {
   }
 
-  @androidx.camera.core.ExperimentalUseCaseGroup public final class UseCaseGroup {
+  public final class UseCaseGroup {
     method public java.util.List<androidx.camera.core.UseCase!> getUseCases();
     method public androidx.camera.core.ViewPort? getViewPort();
   }
 
-  @androidx.camera.core.ExperimentalUseCaseGroup public static final class UseCaseGroup.Builder {
+  public static final class UseCaseGroup.Builder {
     ctor public UseCaseGroup.Builder();
     method public androidx.camera.core.UseCaseGroup.Builder addUseCase(androidx.camera.core.UseCase);
     method public androidx.camera.core.UseCaseGroup build();
     method public androidx.camera.core.UseCaseGroup.Builder setViewPort(androidx.camera.core.ViewPort);
   }
 
-  @androidx.camera.core.ExperimentalUseCaseGroup public final class ViewPort {
+  public final class ViewPort {
     method public android.util.Rational getAspectRatio();
+    method public int getLayoutDirection();
     method public int getRotation();
     method public int getScaleType();
     field public static final int FILL_CENTER = 1; // 0x1
@@ -403,9 +404,11 @@
     field public static final int FIT = 3; // 0x3
   }
 
-  @androidx.camera.core.ExperimentalUseCaseGroup public static final class ViewPort.Builder {
+  public static final class ViewPort.Builder {
     ctor public ViewPort.Builder(android.util.Rational, int);
     method public androidx.camera.core.ViewPort build();
+    method public androidx.camera.core.ViewPort.Builder setLayoutDirection(int);
+    method public androidx.camera.core.ViewPort.Builder setScaleType(int);
   }
 
   public interface ZoomState {
diff --git a/camera/camera-core/api/restricted_current.txt b/camera/camera-core/api/restricted_current.txt
index 46c69c1..9bceab6 100644
--- a/camera/camera-core/api/restricted_current.txt
+++ b/camera/camera-core/api/restricted_current.txt
@@ -303,6 +303,7 @@
     method public int getTargetRotation();
     method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
     method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
+    method public void setTargetRotation(int);
   }
 
   public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
@@ -325,8 +326,10 @@
 
   public final class SurfaceRequest {
     method public void addRequestCancellationListener(java.util.concurrent.Executor, Runnable);
+    method public void clearTransformationInfoListener();
     method public android.util.Size getResolution();
     method public void provideSurface(android.view.Surface, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceRequest.Result!>);
+    method public void setTransformationInfoListener(java.util.concurrent.Executor, androidx.camera.core.SurfaceRequest.TransformationInfoListener);
     method public boolean willNotProvideSurface();
   }
 
@@ -340,6 +343,15 @@
     field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
   }
 
+  @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.TransformationInfo {
+    method public abstract android.graphics.Rect getCropRect();
+    method public abstract int getRotationDegrees();
+  }
+
+  public static interface SurfaceRequest.TransformationInfoListener {
+    method public void onTransformationInfoUpdate(androidx.camera.core.SurfaceRequest.TransformationInfo);
+  }
+
   public class TorchState {
     field public static final int OFF = 0; // 0x0
     field public static final int ON = 1; // 0x1
@@ -348,6 +360,36 @@
   public abstract class UseCase {
   }
 
+  public final class UseCaseGroup {
+    method public java.util.List<androidx.camera.core.UseCase!> getUseCases();
+    method public androidx.camera.core.ViewPort? getViewPort();
+  }
+
+  public static final class UseCaseGroup.Builder {
+    ctor public UseCaseGroup.Builder();
+    method public androidx.camera.core.UseCaseGroup.Builder addUseCase(androidx.camera.core.UseCase);
+    method public androidx.camera.core.UseCaseGroup build();
+    method public androidx.camera.core.UseCaseGroup.Builder setViewPort(androidx.camera.core.ViewPort);
+  }
+
+  public final class ViewPort {
+    method public android.util.Rational getAspectRatio();
+    method public int getLayoutDirection();
+    method public int getRotation();
+    method public int getScaleType();
+    field public static final int FILL_CENTER = 1; // 0x1
+    field public static final int FILL_END = 2; // 0x2
+    field public static final int FILL_START = 0; // 0x0
+    field public static final int FIT = 3; // 0x3
+  }
+
+  public static final class ViewPort.Builder {
+    ctor public ViewPort.Builder(android.util.Rational, int);
+    method public androidx.camera.core.ViewPort build();
+    method public androidx.camera.core.ViewPort.Builder setLayoutDirection(int);
+    method public androidx.camera.core.ViewPort.Builder setScaleType(int);
+  }
+
   public interface ZoomState {
     method public float getLinearZoom();
     method public float getMaxZoomRatio();
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
index 99b6dc6..f6455cf 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
@@ -54,7 +54,6 @@
 import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.OptIn;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
 import androidx.annotation.UiThread;
@@ -192,7 +191,6 @@
     }
 
     @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    @OptIn(markerClass = ExperimentalUseCaseGroup.class)
     SessionConfig.Builder createPipeline(@NonNull String cameraId, @NonNull PreviewConfig config,
             @NonNull Size resolution) {
         Threads.checkMainThread();
@@ -300,14 +298,12 @@
      *                       {@link Surface#ROTATION_180}, or {@link Surface#ROTATION_270}.
      * @see Preview.Builder#setTargetRotation(int)
      */
-    @ExperimentalUseCaseGroup
     public void setTargetRotation(@ImageOutputConfig.RotationValue int targetRotation) {
         if (setTargetRotationInternal(targetRotation)) {
             sendTransformationInfoIfReady();
         }
     }
 
-    @ExperimentalUseCaseGroup
     private void sendTransformationInfoIfReady() {
         // TODO(b/159659392): only send transformation after CameraCaptureCallback
         //  .onCaptureCompleted is called.
@@ -351,7 +347,6 @@
      *                        {@link #setSurfaceProvider(SurfaceProvider)}.
      */
     @UiThread
-    @OptIn(markerClass = ExperimentalUseCaseGroup.class)
     public void setSurfaceProvider(@NonNull Executor executor,
             @Nullable SurfaceProvider surfaceProvider) {
         Threads.checkMainThread();
@@ -528,7 +523,6 @@
      * @hide
      */
     @Override
-    @OptIn(markerClass = ExperimentalUseCaseGroup.class)
     @RestrictTo(Scope.LIBRARY)
     public void setViewPortCropRect(@NonNull Rect viewPortCropRect) {
         super.setViewPortCropRect(viewPortCropRect);
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java
index 6b1ff6e..c6dac13 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceRequest.java
@@ -410,7 +410,6 @@
      * @hide
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    @ExperimentalUseCaseGroup
     public void updateTransformationInfo(@NonNull TransformationInfo transformationInfo) {
         mTransformationInfo = transformationInfo;
         TransformationInfoListener listener = mTransformationInfoListener;
@@ -434,7 +433,6 @@
      * @see TransformationInfoListener
      * @see TransformationInfo
      */
-    @ExperimentalUseCaseGroup
     public void setTransformationInfoListener(@NonNull Executor executor,
             @NonNull TransformationInfoListener listener) {
         mTransformationInfoListener = listener;
@@ -449,7 +447,6 @@
     /**
      * Clears the {@link TransformationInfoListener} set via {@link #setTransformationInfoListener}.
      */
-    @ExperimentalUseCaseGroup
     public void clearTransformationInfoListener() {
         mTransformationInfoListener = null;
         mTransformationInfoExecutor = null;
@@ -475,7 +472,6 @@
      * Listener that receives updates of the {@link TransformationInfo} associated with the
      * {@link SurfaceRequest}.
      */
-    @ExperimentalUseCaseGroup
     public interface TransformationInfoListener {
 
         /**
@@ -653,7 +649,6 @@
      * @see CameraCharacteristics#SENSOR_ORIENTATION
      * @see ViewPort
      */
-    @ExperimentalUseCaseGroup
     @AutoValue
     public abstract static class TransformationInfo {
 
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/UseCaseGroup.java b/camera/camera-core/src/main/java/androidx/camera/core/UseCaseGroup.java
index 21d0c61..cb5459a 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/UseCaseGroup.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/UseCaseGroup.java
@@ -32,7 +32,6 @@
  * {@link UseCaseGroup} usually share some common properties like the FOV defined by
  * {@link ViewPort}.
  */
-@ExperimentalUseCaseGroup
 public final class UseCaseGroup {
 
     @Nullable
@@ -65,7 +64,6 @@
     /**
      * A builder for generating {@link UseCaseGroup}.
      */
-    @ExperimentalUseCaseGroup
     public static final class Builder {
 
         private ViewPort mViewPort;
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ViewPort.java b/camera/camera-core/src/main/java/androidx/camera/core/ViewPort.java
index 7cec098..bd134d5 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ViewPort.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ViewPort.java
@@ -42,7 +42,7 @@
  *
  * <p> If the {@link ViewPort} is used with a {@link ImageCapture} and
  * {@link ImageCapture#takePicture(
- * ImageCapture.OutputFileOptions, Executor, ImageCapture.OnImageSavedCallback)} is called,
+ *ImageCapture.OutputFileOptions, Executor, ImageCapture.OnImageSavedCallback)} is called,
  * the image may be cropped before saving to disk which introduces an additional
  * latency. To avoid the latency and get the uncropped image, please use the in-memory method
  * {@link ImageCapture#takePicture(Executor, ImageCapture.OnImageCapturedCallback)}.
@@ -54,7 +54,6 @@
  * a way that only the area defined by the crop rect is visible to end users. Once the crop rect
  * is applied, all the use cases will produce the same image with possibly different resolutions.
  */
-@ExperimentalUseCaseGroup
 public final class ViewPort {
 
     /**
@@ -63,9 +62,9 @@
      * @hide
      * @see android.util.LayoutDirection
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @IntDef({android.util.LayoutDirection.LTR, android.util.LayoutDirection.RTL})
     @Retention(RetentionPolicy.SOURCE)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public @interface LayoutDirection {
     }
 
@@ -74,9 +73,9 @@
      *
      * @hide
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @IntDef({FILL_START, FILL_CENTER, FILL_END, FIT})
     @Retention(RetentionPolicy.SOURCE)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public @interface ScaleType {
     }
 
@@ -191,11 +190,8 @@
 
     /**
      * Gets the layout direction of the {@link ViewPort}.
-     *
-     * @hide
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    @ScaleType
+    @LayoutDirection
     public int getLayoutDirection() {
         return mLayoutDirection;
     }
@@ -203,7 +199,6 @@
     /**
      * Builder for {@link ViewPort}.
      */
-    @ExperimentalUseCaseGroup
     public static final class Builder {
 
         private static final int DEFAULT_LAYOUT_DIRECTION = android.util.LayoutDirection.LTR;
@@ -253,14 +248,11 @@
         }
 
         /**
-         * Sets the {@link ScaleType} of the {@link ViewPort}.
+         * Sets the scale type of the {@link ViewPort}.
          *
-         * <p> The value is used by {@link UseCase} to calculate the
-         * {@link UseCase#getViewPortCropRect()}.
+         * <p> The value is used by {@link UseCase} to calculate the crop rect.
          *
          * <p> The default value is {@link #FILL_CENTER} if not set.
-         *
-         * @hide
          */
         @NonNull
         public Builder setScaleType(@ScaleType int scaleType) {
@@ -271,12 +263,10 @@
         /**
          * Sets the layout direction of the {@link ViewPort}.
          *
-         * <p> The {@link LayoutDirection} decides the start and the end of the crop rect if
-         * the {@link ScaleType} is {@link #FILL_END} or {@link #FILL_START}.
+         * <p> The layout direction decides the start and the end of the crop rect if
+         * the scale type is {@link #FILL_END} or {@link #FILL_START}.
          *
          * <p> The default value is {@link android.util.LayoutDirection#LTR} if not set.
-         *
-         * @hide
          */
         @NonNull
         public Builder setLayoutDirection(@LayoutDirection int layoutDirection) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageOutputConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageOutputConfig.java
index a78c0a7..62d5e09 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageOutputConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/ImageOutputConfig.java
@@ -25,7 +25,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.camera.core.AspectRatio;
-import androidx.camera.core.ExperimentalUseCaseGroup;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -326,7 +325,6 @@
      */
     @IntDef({0, 90, 180, 270})
     @Retention(RetentionPolicy.SOURCE)
-    @ExperimentalUseCaseGroup
     @interface RotationDegreesValue {
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
index d830cd8..ceb5d01 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
@@ -22,7 +22,6 @@
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.OptIn;
 import androidx.camera.core.Camera;
 import androidx.camera.core.CameraControl;
 import androidx.camera.core.CameraInfo;
@@ -173,7 +172,6 @@
      * @throws CameraException Thrown if the combination of newly added UseCases and the
      *                         currently added UseCases exceed the capability of the camera.
      */
-    @OptIn(markerClass = androidx.camera.core.ExperimentalUseCaseGroup.class)
     public void addUseCases(@NonNull Collection<UseCase> useCases) throws CameraException {
         synchronized (mLock) {
             List<UseCase> newUseCases = new ArrayList<>();
@@ -364,7 +362,6 @@
         return suggestedResolutions;
     }
 
-    @OptIn(markerClass = androidx.camera.core.ExperimentalUseCaseGroup.class)
     private void updateViewPort(@NonNull Map<UseCase, Size> suggestedResolutionsMap,
             @NonNull Collection<UseCase> useCases) {
         synchronized (mLock) {
diff --git a/camera/camera-lifecycle/api/current.txt b/camera/camera-lifecycle/api/current.txt
index bac9afa..c15b6d1 100644
--- a/camera/camera-lifecycle/api/current.txt
+++ b/camera/camera-lifecycle/api/current.txt
@@ -3,6 +3,7 @@
 
   public final class ProcessCameraProvider {
     method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+    method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCaseGroup);
     method public java.util.List<androidx.camera.core.CameraInfo!> getAvailableCameraInfos();
     method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
     method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
diff --git a/camera/camera-lifecycle/api/public_plus_experimental_current.txt b/camera/camera-lifecycle/api/public_plus_experimental_current.txt
index 58a2fdc..636ebcd 100644
--- a/camera/camera-lifecycle/api/public_plus_experimental_current.txt
+++ b/camera/camera-lifecycle/api/public_plus_experimental_current.txt
@@ -9,7 +9,7 @@
 
   public final class ProcessCameraProvider implements androidx.camera.core.CameraProvider {
     method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
-    method @MainThread @androidx.camera.core.ExperimentalUseCaseGroup public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCaseGroup);
+    method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCaseGroup);
     method @androidx.camera.lifecycle.ExperimentalCameraProviderConfiguration public static void configureInstance(androidx.camera.core.CameraXConfig);
     method public java.util.List<androidx.camera.core.CameraInfo!> getAvailableCameraInfos();
     method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
diff --git a/camera/camera-lifecycle/api/restricted_current.txt b/camera/camera-lifecycle/api/restricted_current.txt
index 5ef0e75..f4ee4e4 100644
--- a/camera/camera-lifecycle/api/restricted_current.txt
+++ b/camera/camera-lifecycle/api/restricted_current.txt
@@ -3,6 +3,7 @@
 
   public final class ProcessCameraProvider implements androidx.camera.core.CameraProvider {
     method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+    method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCaseGroup);
     method public java.util.List<androidx.camera.core.CameraInfo!> getAvailableCameraInfos();
     method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
     method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
diff --git a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
index 59f3692..29836d4 100644
--- a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
+++ b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
@@ -23,7 +23,6 @@
 import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.OptIn;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
 import androidx.camera.core.Camera;
@@ -33,7 +32,6 @@
 import androidx.camera.core.CameraSelector;
 import androidx.camera.core.CameraX;
 import androidx.camera.core.CameraXConfig;
-import androidx.camera.core.ExperimentalUseCaseGroup;
 import androidx.camera.core.ImageAnalysis;
 import androidx.camera.core.ImageCapture;
 import androidx.camera.core.InitializationException;
@@ -278,10 +276,9 @@
      * @throws IllegalArgumentException If the provided camera selector is unable to resolve a
      *                                  camera to be used for the given use cases.
      */
-    @SuppressWarnings({"lambdaLast", "deprecation"})
+    @SuppressWarnings({"lambdaLast"})
     @MainThread
     @NonNull
-    @OptIn(markerClass = ExperimentalUseCaseGroup.class)
     public Camera bindToLifecycle(@NonNull LifecycleOwner lifecycleOwner,
             @NonNull CameraSelector cameraSelector,
             @NonNull UseCase... useCases) {
@@ -300,8 +297,7 @@
      * the {@link UseCaseGroup} in the latest
      * {@link #bindToLifecycle(LifecycleOwner, CameraSelector, UseCaseGroup)} call.
      */
-    @ExperimentalUseCaseGroup
-    @SuppressWarnings({"lambdaLast", "deprecation"})
+    @SuppressWarnings({"lambdaLast"})
     @MainThread
     @NonNull
     public Camera bindToLifecycle(@NonNull LifecycleOwner lifecycleOwner,
@@ -367,13 +363,10 @@
      *                                  or method is not called on main thread.
      * @throws IllegalArgumentException If the provided camera selector is unable to resolve a
      *                                  camera to be used for the given use cases.
-     * @hide
      */
-    @SuppressWarnings({"lambdaLast", "unused", "deprecation"})
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @ExperimentalUseCaseGroup
+    @SuppressWarnings({"lambdaLast", "unused"})
     @NonNull
-    public Camera bindToLifecycle(
+    Camera bindToLifecycle(
             @NonNull LifecycleOwner lifecycleOwner,
             @NonNull CameraSelector cameraSelector,
             @Nullable ViewPort viewPort,
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
index 8ed9a49..fdf68c7 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapture.java
@@ -288,7 +288,7 @@
         return Builder.fromConfig(config);
     }
 
-    @ExperimentalUseCaseGroup
+    @OptIn(markerClass = ExperimentalUseCaseGroup.class)
     private void sendTransformationInfoIfReady(@Nullable Size resolution) {
         CameraInternal cameraInternal = getCamera();
         SurfaceRequest surfaceRequest = mSurfaceRequest;
@@ -317,7 +317,6 @@
     }
 
     @UiThread
-    @OptIn(markerClass = ExperimentalUseCaseGroup.class)
     @NonNull
     private SessionConfig.Builder createPipeline(@NonNull String cameraId,
             @NonNull VideoCaptureConfig<T> config,
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
index bf2dd58..105d396 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
@@ -57,7 +57,6 @@
 import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.OptIn;
 import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.camera.core.Camera;
@@ -65,7 +64,6 @@
 import androidx.camera.core.CameraInfo;
 import androidx.camera.core.CameraSelector;
 import androidx.camera.core.DisplayOrientedMeteringPointFactory;
-import androidx.camera.core.ExperimentalUseCaseGroup;
 import androidx.camera.core.ExposureState;
 import androidx.camera.core.FocusMeteringAction;
 import androidx.camera.core.FocusMeteringResult;
@@ -839,7 +837,6 @@
     /**
      * Binds use cases to the current lifecycle.
      */
-    @OptIn(markerClass = ExperimentalUseCaseGroup.class)
     private Camera bindToLifecycleSafely(List<UseCase> useCases) {
         ViewPort viewPort = new ViewPort.Builder(new Rational(mViewFinder.getWidth(),
                 mViewFinder.getHeight()),
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLRenderer.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLRenderer.java
index 6793c95..3285db1 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLRenderer.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLRenderer.java
@@ -28,9 +28,7 @@
 import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.OptIn;
 import androidx.annotation.WorkerThread;
-import androidx.camera.core.ExperimentalUseCaseGroup;
 import androidx.camera.core.Preview;
 import androidx.concurrent.futures.CallbackToFutureAdapter;
 import androidx.core.util.Consumer;
@@ -108,7 +106,6 @@
      * @return A {@link ListenableFuture} that signals the new surface is ready to be used in the
      * renderer for the input Preview use-case.
      */
-    @OptIn(markerClass = ExperimentalUseCaseGroup.class)
     @MainThread
     @SuppressWarnings("ObjectToString")
     @NonNull