Merge "Make userCursor public (but restricted) to be able to use it from test apps." into androidx-main
diff --git a/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/AnnotatedJavaClass.java b/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/AnnotatedJavaClass.java
index 217333f..f23ddb5 100644
--- a/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/AnnotatedJavaClass.java
+++ b/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/AnnotatedJavaClass.java
@@ -20,7 +20,7 @@
  * Class which is experimental.
  */
 @ExperimentalJavaAnnotation
-class AnnotatedJavaClass {
+public class AnnotatedJavaClass {
     public static final int FIELD_STATIC = -1;
 
     public static int methodStatic() {
diff --git a/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/bar/RegressionTestJava219525415.java b/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/bar/RegressionTestJava219525415.java
new file mode 100644
index 0000000..62bc5ae
--- /dev/null
+++ b/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/bar/RegressionTestJava219525415.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package sample.optin.bar;
+
+import sample.optin.AnnotatedJavaClass;
+
+/**
+ * Regression test for b/219525415 where the @OptIn annotation did not target packages.
+ */
+@SuppressWarnings("unused")
+public class RegressionTestJava219525415 {
+
+    /**
+     * Safe usage of class-level @RequiresOptIn due to package-level opt-in.
+     */
+    int safeClassRequiresOptIn() {
+        AnnotatedJavaClass experimentalObject = new AnnotatedJavaClass();
+        return experimentalObject.method();
+    }
+}
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/response/package-info.java b/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/bar/package-info.java
similarity index 72%
rename from health/health-data-client/src/main/java/androidx/health/data/client/response/package-info.java
rename to annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/bar/package-info.java
index 02aa6f7..3224d09 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/response/package-info.java
+++ b/annotation/annotation-experimental-lint/integration-tests/src/main/java/sample/optin/bar/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-/** @hide */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-package androidx.health.data.client.response;
+@OptIn(markerClass = ExperimentalJavaAnnotation.class)
+package sample.optin.bar;
 
-import androidx.annotation.RestrictTo;
+import androidx.annotation.OptIn;
+
+import sample.optin.ExperimentalJavaAnnotation;
diff --git a/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt b/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
index 06524f1..65be75b 100644
--- a/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
+++ b/annotation/annotation-experimental-lint/src/main/java/androidx/annotation/experimental/lint/ExperimentalDetector.kt
@@ -844,7 +844,7 @@
 ): Boolean = optInFqNames.any { optInFqName ->
     annotations.any { annotation ->
         annotation.hasQualifiedName(optInFqName) &&
-            ((annotation as? UAnnotation)?.hasMatchingAttributeValueClass(
+            ((annotation.toUElement() as? UAnnotation)?.hasMatchingAttributeValueClass(
                 "markerClass",
                 annotationFqName,
             ) ?: false)
diff --git a/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/RequiresOptInDetectorTest.kt b/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/RequiresOptInDetectorTest.kt
index ac7e6b3..463c143 100644
--- a/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/RequiresOptInDetectorTest.kt
+++ b/annotation/annotation-experimental-lint/src/test/kotlin/androidx/annotation/experimental/lint/RequiresOptInDetectorTest.kt
@@ -422,6 +422,29 @@
         check(*input).expect(expected)
     }
 
+    /**
+     * Regression test for b/219525415 where the @OptIn annotation did not target packages.
+     */
+    @Test
+    fun regressionTestJava219525415() {
+        val input = arrayOf(
+            SAMPLE_FOO_PACKAGE_INFO,
+            SAMPLE_BAR_PACKAGE_INFO,
+            javaSample("sample.optin.AnnotatedJavaClass"),
+            javaSample("sample.optin.ExperimentalJavaAnnotation"),
+            javaSample("sample.optin.bar.RegressionTestJava219525415"),
+            javaSample("sample.optin.foo.AnnotatedJavaPackage")
+        )
+
+        /* ktlint-disable max-line-length */
+        val expected = """
+No warnings.
+        """.trimIndent()
+        /* ktlint-enable max-line-length */
+
+        check(*input).expect(expected)
+    }
+
     /* ktlint-disable max-line-length */
     companion object {
         /**
@@ -432,7 +455,7 @@
          */
         val ANDROIDX_REQUIRES_OPT_IN_KT: TestFile = kotlin(
             """
-            package androidx.annotation;
+            package androidx.annotation
 
             import kotlin.annotation.Retention
             import kotlin.annotation.Target
@@ -458,7 +481,7 @@
          */
         val ANDROIDX_OPT_IN_KT: TestFile = kotlin(
             """
-            package androidx.annotation;
+            package androidx.annotation
 
             import kotlin.annotation.Retention
             import kotlin.annotation.Target
@@ -490,6 +513,7 @@
          * from source code. This is generated from a single-class JAR using toBase64gzip(File).
          *
          * To re-generate this:
+         * (if linux). alias pbcopy='xclip -selection clipboard'
          * 1. ./gradlew :annotation:annotation-experimental-lint-integration-tests:assemble
          * 2. mkdir -p temp/sample/optin/foo/
          * 3. cp ../../out/androidx/annotation/annotation-experimental-lint-integration-tests/build/intermediates/javac/debug/classes/sample/optin/foo/package-info.class temp/sample/optin/foo/
@@ -501,6 +525,16 @@
             "libs/sample.optin.foo.package-info.jar",
             "UEsDBBQACAgIABRYjVIAAAAAAAAAAAAAAAAJAAQATUVUQS1JTkYv/soAAAMAUEsHCAAAAAACAAAAAAAAAFBLAwQUAAgICAAUWI1SAAAAAAAAAAAAAAAAFAAAAE1FVEEtSU5GL01BTklGRVNULk1G803My0xLLS7RDUstKs7Mz7NSMNQz4OVyLkpNLElN0XWqBAoARfRMFDT8ixKTc1IVnPOLCvKLEkuAijV5uXi5AFBLBwiVBramQAAAAEIAAABQSwMECgAACAAAOVeNUgAAAAAAAAAAAAAAAAcAAABzYW1wbGUvUEsDBAoAAAgAADlXjVIAAAAAAAAAAAAAAAANAAAAc2FtcGxlL29wdGluL1BLAwQKAAAIAAA7V41SAAAAAAAAAAAAAAAAEQAAAHNhbXBsZS9vcHRpbi9mb28vUEsDBBQACAgIADtXjVIAAAAAAAAAAAAAAAAjAAAAc2FtcGxlL29wdGluL2Zvby9wYWNrYWdlLWluZm8uY2xhc3NVjcEOwUAYhGeLFicuLuIBHNiLm5MDCZFIeIJts222tv9u2m3j2Rw8gIcSiwPmMHOYbzL3x/UGYIFehChCl6F/MnWZyI3SkmFoRXIWmZwpSs08F41gGB9rcqqQW2pUpWItV0TGCacMVQzTfSUKqyU31ini64uVpYfJCb3z8y+7ZJj8oakx/PeOYfA65FpQxg9xLhM3AhgCfBSg9fY2Oj5D34TAE1BLBwjeUT3SpAAAANAAAABQSwECFAAUAAgICAAUWI1SAAAAAAIAAAAAAAAACQAEAAAAAAAAAAAAAAAAAAAATUVUQS1JTkYv/soAAFBLAQIUABQACAgIABRYjVKVBramQAAAAEIAAAAUAAAAAAAAAAAAAAAAAD0AAABNRVRBLUlORi9NQU5JRkVTVC5NRlBLAQIKAAoAAAgAADlXjVIAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAAL8AAABzYW1wbGUvUEsBAgoACgAACAAAOVeNUgAAAAAAAAAAAAAAAA0AAAAAAAAAAAAAAAAA5AAAAHNhbXBsZS9vcHRpbi9QSwECCgAKAAAIAAA7V41SAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAPAQAAc2FtcGxlL29wdGluL2Zvby9QSwECFAAUAAgICAA7V41S3lE90qQAAADQAAAAIwAAAAAAAAAAAAAAAAA+AQAAc2FtcGxlL29wdGluL2Zvby9wYWNrYWdlLWluZm8uY2xhc3NQSwUGAAAAAAYABgB9AQAAMwIAAAAA"
         )
+
+        /**
+         * [TestFile] containing the package-level annotation for the sample.optin.bar package.
+         *
+         * See [SAMPLE_FOO_PACKAGE_INFO] for details on how to re-generate this data.
+         */
+        val SAMPLE_BAR_PACKAGE_INFO: TestFile = base64gzip(
+            "libs/sample.optin.bar.package-info.jar",
+            "UEsDBBQACAgIAEZucVQAAAAAAAAAAAAAAAAJAAQATUVUQS1JTkYv/soAAAMAUEsHCAAAAAACAAAAAAAAAFBLAwQUAAgICABGbnFUAAAAAAAAAAAAAAAAFAAAAE1FVEEtSU5GL01BTklGRVNULk1G803My0xLLS7RDUstKs7Mz7NSMNQz4OVyLkpNLElN0XWqBAoARfQMjRQ03PPz03NSFTzzkvU0ebl4uQBQSwcIy/5xeDsAAAA8AAAAUEsDBAoAAAgAAC5bcVQAAAAAAAAAAAAAAAAHAAAAc2FtcGxlL1BLAwQKAAAIAAAuW3FUAAAAAAAAAAAAAAAADQAAAHNhbXBsZS9vcHRpbi9QSwMECgAACAAALltxVAAAAAAAAAAAAAAAABEAAABzYW1wbGUvb3B0aW4vYmFyL1BLAwQUAAgICAA1bnFUAAAAAAAAAAAAAAAAIwAAAHNhbXBsZS9vcHRpbi9iYXIvcGFja2FnZS1pbmZvLmNsYXNzVU5LagJBEH1tPhMVgtm4CTlAFrE32WUVxIBBEHSZVc1MZeixp7rpacWzZZED5FBiqxCTgqqCep96P7uvbwDP6GfoZugp9JZuHQp+M5YV7jwVK6r4ycinG9W0IYX7xVqiaXgqG9Oa3PKriIsUjZM2oTOSMjhTbjX93vXcx6m8KPQbCisOY0tt4j7OWmq8Ze18NKInW88hGUsk+55enX2T8uEfNaeg/0ZTGBzCaUtS6XlecxGHgEIHp+rg4jgvcZX2bUKuU2cfUAVu9lBLBwjs0mNTygAAAAQBAABQSwECFAAUAAgICABGbnFUAAAAAAIAAAAAAAAACQAEAAAAAAAAAAAAAAAAAAAATUVUQS1JTkYv/soAAFBLAQIUABQACAgIAEZucVTL/nF4OwAAADwAAAAUAAAAAAAAAAAAAAAAAD0AAABNRVRBLUlORi9NQU5JRkVTVC5NRlBLAQIKAAoAAAgAAC5bcVQAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAALoAAABzYW1wbGUvUEsBAgoACgAACAAALltxVAAAAAAAAAAAAAAAAA0AAAAAAAAAAAAAAAAA3wAAAHNhbXBsZS9vcHRpbi9QSwECCgAKAAAIAAAuW3FUAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAKAQAAc2FtcGxlL29wdGluL2Jhci9QSwECFAAUAAgICAA1bnFU7NJjU8oAAAAEAQAAIwAAAAAAAAAAAAAAAAA5AQAAc2FtcGxlL29wdGluL2Jhci9wYWNrYWdlLWluZm8uY2xhc3NQSwUGAAAAAAYABgB9AQAAVAIAAAAA"
+        )
     }
     /* ktlint-enable max-line-length */
 }
diff --git a/annotation/annotation-experimental/api/current.txt b/annotation/annotation-experimental/api/current.txt
index 86a3b56..174fc9c 100644
--- a/annotation/annotation-experimental/api/current.txt
+++ b/annotation/annotation-experimental/api/current.txt
@@ -1,7 +1,7 @@
 // Signature format: 4.0
 package androidx.annotation {
 
-  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.TYPEALIAS}) public @interface OptIn {
+  @java.lang.annotation.Target({java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PACKAGE, java.lang.annotation.ElementType.TYPE}) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.TYPEALIAS}) public @interface OptIn {
     method public abstract kotlin.reflect.KClass<? extends java.lang.annotation.Annotation>[] markerClass();
     property public abstract kotlin.reflect.KClass<? extends java.lang.annotation.Annotation>![] markerClass;
   }
diff --git a/annotation/annotation-experimental/api/public_plus_experimental_current.txt b/annotation/annotation-experimental/api/public_plus_experimental_current.txt
index 86a3b56..174fc9c 100644
--- a/annotation/annotation-experimental/api/public_plus_experimental_current.txt
+++ b/annotation/annotation-experimental/api/public_plus_experimental_current.txt
@@ -1,7 +1,7 @@
 // Signature format: 4.0
 package androidx.annotation {
 
-  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.TYPEALIAS}) public @interface OptIn {
+  @java.lang.annotation.Target({java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PACKAGE, java.lang.annotation.ElementType.TYPE}) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.TYPEALIAS}) public @interface OptIn {
     method public abstract kotlin.reflect.KClass<? extends java.lang.annotation.Annotation>[] markerClass();
     property public abstract kotlin.reflect.KClass<? extends java.lang.annotation.Annotation>![] markerClass;
   }
diff --git a/annotation/annotation-experimental/api/restricted_current.txt b/annotation/annotation-experimental/api/restricted_current.txt
index 86a3b56..174fc9c 100644
--- a/annotation/annotation-experimental/api/restricted_current.txt
+++ b/annotation/annotation-experimental/api/restricted_current.txt
@@ -1,7 +1,7 @@
 // Signature format: 4.0
 package androidx.annotation {
 
-  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.TYPEALIAS}) public @interface OptIn {
+  @java.lang.annotation.Target({java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PACKAGE, java.lang.annotation.ElementType.TYPE}) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.TYPEALIAS}) public @interface OptIn {
     method public abstract kotlin.reflect.KClass<? extends java.lang.annotation.Annotation>[] markerClass();
     property public abstract kotlin.reflect.KClass<? extends java.lang.annotation.Annotation>![] markerClass;
   }
diff --git a/annotation/annotation-experimental/src/main/java/androidx/annotation/OptIn.kt b/annotation/annotation-experimental/src/main/java/androidx/annotation/OptIn.kt
index 9a7bf32..aa75089 100644
--- a/annotation/annotation-experimental/src/main/java/androidx/annotation/OptIn.kt
+++ b/annotation/annotation-experimental/src/main/java/androidx/annotation/OptIn.kt
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
+@file:Suppress("DEPRECATED_JAVA_ANNOTATION")
+
 package androidx.annotation
 
+import java.lang.annotation.ElementType
 import kotlin.annotation.Retention
 import kotlin.annotation.Target
 import kotlin.reflect.KClass
@@ -38,6 +41,14 @@
     AnnotationTarget.FILE,
     AnnotationTarget.TYPEALIAS
 )
+@java.lang.annotation.Target(
+    ElementType.CONSTRUCTOR,
+    ElementType.FIELD,
+    ElementType.LOCAL_VARIABLE,
+    ElementType.METHOD,
+    ElementType.PACKAGE,
+    ElementType.TYPE,
+)
 public annotation class OptIn(
     /**
      * Defines the opt-in API(s) whose usage this annotation allows.
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRootImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRootImplPlugin.kt
index 2e51ac8..46578bf 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRootImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRootImplPlugin.kt
@@ -193,7 +193,7 @@
             // We're mostly zipping a bunch of .apk files that are already compressed
             it.entryCompression = ZipEntryCompression.STORED
             // Archive is greater than 4Gb :O
-            it.isZip64()
+            it.isZip64 = true
         }
         project.tasks.register(
             ZIP_CONSTRAINED_TEST_CONFIGS_WITH_APKS_TASK, Zip::class.java
@@ -204,7 +204,7 @@
             // We're mostly zipping a bunch of .apk files that are already compressed
             it.entryCompression = ZipEntryCompression.STORED
             // Archive is greater than 4Gb :O
-            it.isZip64()
+            it.isZip64 = true
         }
 
         AffectedModuleDetector.configure(gradle, this)
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
index f2f0ef3..bf6628a 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
@@ -82,7 +82,9 @@
     }
 
     @Rule
-    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
     private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
     private CameraUseCaseAdapter mCamera;
     private UseCase mBoundUseCase;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.kt
index 3310d6b..a351980 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.kt
@@ -30,6 +30,7 @@
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.core.internal.CameraUseCaseAdapter
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.CameraXUtil
 import androidx.camera.testing.GLUtil
 import androidx.camera.testing.SurfaceTextureProvider
@@ -41,6 +42,14 @@
 import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.Executor
+import java.util.concurrent.Executors
+import java.util.concurrent.Semaphore
+import java.util.concurrent.ThreadFactory
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeoutException
+import java.util.concurrent.atomic.AtomicReference
 import org.junit.After
 import org.junit.Assume
 import org.junit.Before
@@ -50,21 +59,15 @@
 import org.mockito.ArgumentMatchers
 import org.mockito.Mockito
 import org.mockito.invocation.InvocationOnMock
-import java.util.concurrent.ExecutionException
-import java.util.concurrent.Executor
-import java.util.concurrent.Executors
-import java.util.concurrent.Semaphore
-import java.util.concurrent.ThreadFactory
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.TimeoutException
-import java.util.concurrent.atomic.AtomicReference
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
 @SdkSuppress(minSdkVersion = 21)
 class PreviewTest {
     @get:Rule
-    var cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
     private val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
     private var defaultBuilder: Preview.Builder? = null
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTest.kt
index 5bd397e..95253ee 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTest.kt
@@ -34,6 +34,7 @@
 import androidx.camera.core.internal.CameraUseCaseAdapter
 import androidx.camera.testing.AudioUtil
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.CameraXUtil
 import androidx.camera.testing.SurfaceTextureProvider.SurfaceTextureCallback
 import androidx.camera.testing.SurfaceTextureProvider.createSurfaceTextureProvider
@@ -46,21 +47,20 @@
 import androidx.test.rule.GrantPermissionRule
 import androidx.testutils.assertThrows
 import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.util.concurrent.TimeUnit
 import org.junit.After
 import org.junit.Assume.assumeFalse
 import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.any
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.timeout
 import org.mockito.Mockito.verify
-import java.io.File
-import java.util.concurrent.TimeUnit
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
@@ -74,7 +74,9 @@
     val useRecordingResource = CameraUtil.checkVideoRecordingResource()
 
     @get:Rule
-    val useCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val permissionRule: GrantPermissionRule =
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTestWithoutAudioPermissionTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTestWithoutAudioPermissionTest.kt
index 7fdbaa4..8a7b21a 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTestWithoutAudioPermissionTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTestWithoutAudioPermissionTest.kt
@@ -32,6 +32,7 @@
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.core.internal.CameraUseCaseAdapter
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.CameraXUtil
 import androidx.camera.testing.SurfaceTextureProvider
 import androidx.core.content.ContextCompat
@@ -42,18 +43,17 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.GrantPermissionRule
 import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.util.concurrent.TimeUnit
 import org.junit.After
 import org.junit.Assume
 import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers
 import org.mockito.Mockito
-import java.io.File
-import java.util.concurrent.TimeUnit
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
@@ -63,7 +63,9 @@
         const val TAG: String = "VideoCaptureTestWithoutAudioPermission"
     }
     @get:Rule
-    val useCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val permissionRule: GrantPermissionRule =
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplDeviceTest.java
index 964ea8a..fe6d5dd 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplDeviceTest.java
@@ -109,7 +109,9 @@
 @SdkSuppress(minSdkVersion = 21)
 public final class Camera2CameraControlImplDeviceTest {
     @Rule
-    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     private Camera2CameraControlImpl mCamera2CameraControlImpl;
     private CameraControlInternal.ControlUpdateCallback mControlUpdateCallback;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplCameraReopenTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplCameraReopenTest.kt
index 4b393b5..7c79a87 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplCameraReopenTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplCameraReopenTest.kt
@@ -25,6 +25,7 @@
 import androidx.annotation.GuardedBy
 import androidx.annotation.RequiresApi
 import androidx.camera.camera2.AsyncCameraDevice
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.internal.compat.CameraAccessExceptionCompat
 import androidx.camera.camera2.internal.compat.CameraManagerCompat
 import androidx.camera.core.CameraSelector
@@ -36,12 +37,19 @@
 import androidx.camera.core.impl.utils.MainThreadAsyncHandler
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.core.os.HandlerCompat
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.Executor
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
+import kotlin.math.ceil
 import org.junit.After
 import org.junit.AfterClass
 import org.junit.Assume
@@ -50,12 +58,6 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import java.util.concurrent.ExecutionException
-import java.util.concurrent.Executor
-import java.util.concurrent.ExecutorService
-import java.util.concurrent.Semaphore
-import java.util.concurrent.TimeUnit
-import kotlin.math.ceil
 import org.mockito.Mockito.mock
 
 /** Contains [Camera2CameraImpl] tests for reopening the camera with failures.  */
@@ -64,7 +66,9 @@
 @SdkSuppress(minSdkVersion = 21)
 class Camera2CameraImplCameraReopenTest {
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
     private var camera2CameraImpl: Camera2CameraImpl? = null
     private var cameraId: String? = null
     private var anotherCameraDevice: AsyncCameraDevice? = null
@@ -589,7 +593,9 @@
                 field = value
             }
         }
-    @Volatile var shouldEmitCameraInUseError = false
+    @Volatile
+    var shouldEmitCameraInUseError = false
+
     @GuardedBy("lock")
     var deviceStateCallback: CameraDeviceCallbackWrapper? = null
         get() {
@@ -644,8 +650,10 @@
             if (shouldFailCameraOpen) {
                 if (shouldEmitCameraInUseError) {
                     executor.execute {
-                        callback.onError(mock(CameraDevice::class.java),
-                            CameraDevice.StateCallback.ERROR_CAMERA_IN_USE)
+                        callback.onError(
+                            mock(CameraDevice::class.java),
+                            CameraDevice.StateCallback.ERROR_CAMERA_IN_USE
+                        )
                     }
                 }
                 // Throw any exception
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplForceOpenCameraTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplForceOpenCameraTest.kt
index 9f89f38..1d1910c 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplForceOpenCameraTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplForceOpenCameraTest.kt
@@ -23,6 +23,7 @@
 import android.os.Handler
 import android.os.HandlerThread
 import androidx.camera.camera2.AsyncCameraDevice
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.internal.compat.CameraManagerCompat
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.Logger
@@ -31,6 +32,7 @@
 import androidx.camera.core.impl.Observable.Observer
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.core.os.HandlerCompat
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -38,6 +40,9 @@
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
 import com.google.common.util.concurrent.ListenableFuture
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
 import org.junit.After
 import org.junit.AfterClass
 import org.junit.Assume.assumeFalse
@@ -45,11 +50,7 @@
 import org.junit.BeforeClass
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
-import java.util.concurrent.ExecutorService
-import java.util.concurrent.Semaphore
-import java.util.concurrent.TimeUnit
 
 /**
  * Tests [Camera2CameraImpl]'s force opening camera behavior.
@@ -68,7 +69,9 @@
 class Camera2CameraImplForceOpenCameraTest {
 
     @get:Rule
-    val mCameraRule: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private lateinit var cameraId: String
     private lateinit var camera2Camera: AsyncCameraDevice
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplStateTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplStateTest.kt
index d119e32..5e7316d 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplStateTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplStateTest.kt
@@ -20,6 +20,7 @@
 import android.hardware.camera2.CameraManager
 import android.os.Handler
 import android.os.HandlerThread
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.internal.compat.CameraAccessExceptionCompat
 import androidx.camera.camera2.internal.compat.CameraAccessExceptionCompat.CAMERA_UNAVAILABLE_DO_NOT_DISTURB
 import androidx.camera.camera2.internal.compat.CameraManagerCompat
@@ -34,6 +35,7 @@
 import androidx.camera.core.impl.utils.MainThreadAsyncHandler
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.fakes.FakeCamera
 import androidx.core.os.HandlerCompat
 import androidx.lifecycle.Observer
@@ -41,6 +43,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
+import java.util.concurrent.Executor
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
@@ -55,9 +60,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito
-import java.util.concurrent.Executor
-import java.util.concurrent.Semaphore
-import java.util.concurrent.TimeUnit
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
@@ -65,7 +67,9 @@
 internal class Camera2CameraImplStateTest {
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private lateinit var cameraId: String
     private lateinit var camera: Camera2CameraImpl
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
index e207dbf..8471ac9 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
@@ -43,6 +43,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.camera.camera2.Camera2Config;
 import androidx.camera.camera2.internal.compat.CameraManagerCompat;
 import androidx.camera.camera2.internal.util.SemaphoreReleasingCamera2Callbacks;
 import androidx.camera.camera2.interop.Camera2Interop;
@@ -120,8 +121,9 @@
     static ExecutorService sCameraExecutor;
 
     @Rule
-    public TestRule mCameraRule = CameraUtil.grantCameraPermissionAndPreTest();
-
+    public TestRule mCameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     private ArrayList<FakeUseCase> mFakeUseCases = new ArrayList<>();
     private Camera2CameraImpl mCamera2CameraImpl;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2ImplCameraXTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2ImplCameraXTest.java
index 7c1d472..051af05 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2ImplCameraXTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2ImplCameraXTest.java
@@ -91,7 +91,9 @@
             new CameraSelector.Builder().requireLensFacing(DEFAULT_LENS_FACING).build();
 
     @Rule
-    public TestRule mCameraRule = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mCameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     private CameraDevice.StateCallback mDeviceStateCallback;
     private FakeLifecycleOwner mLifecycle;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2RequestProcessorTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2RequestProcessorTest.kt
index 093d340..3efb25f 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2RequestProcessorTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2RequestProcessorTest.kt
@@ -28,6 +28,7 @@
 import android.os.Handler
 import android.os.Looper
 import android.view.Surface
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.impl.Camera2CameraCaptureResultConverter
 import androidx.camera.camera2.internal.util.RequestProcessorRequest
 import androidx.camera.camera2.interop.CaptureRequestOptions
@@ -38,12 +39,16 @@
 import androidx.camera.core.impl.SessionProcessorSurface
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.concurrent.futures.await
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.Executor
+import java.util.concurrent.ScheduledExecutorService
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.runBlocking
@@ -53,9 +58,6 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.Executor
-import java.util.concurrent.ScheduledExecutorService
 
 const val CAMERA_ID = "0"
 const val PREVIEW_OUTPUT_CONFIG_ID = 1
@@ -69,7 +71,9 @@
 @SdkSuppress(minSdkVersion = 21)
 class Camera2RequestProcessorTest {
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private lateinit var cameraDeviceHolder: CameraUtil.CameraDeviceHolder
     private lateinit var captureSessionRepository: CaptureSessionRepository
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/CaptureSessionTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/CaptureSessionTest.java
index 1ba8b54..0610617 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/CaptureSessionTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/CaptureSessionTest.java
@@ -50,6 +50,7 @@
 import android.view.Surface;
 
 import androidx.annotation.NonNull;
+import androidx.camera.camera2.Camera2Config;
 import androidx.camera.camera2.impl.Camera2ImplConfig;
 import androidx.camera.camera2.impl.CameraEventCallback;
 import androidx.camera.camera2.impl.CameraEventCallbacks;
@@ -131,7 +132,9 @@
     private final List<CaptureSession> mCaptureSessions = new ArrayList<>();
 
     @Rule
-    public TestRule mUseCameraRule = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     @BeforeClass
     public static void setUpClass() {
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java
index 9b8d57bd..1e49ba3 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java
@@ -41,6 +41,7 @@
 import android.view.Surface;
 
 import androidx.annotation.NonNull;
+import androidx.camera.camera2.Camera2Config;
 import androidx.camera.camera2.internal.compat.CameraManagerCompat;
 import androidx.camera.camera2.internal.util.SemaphoreReleasingCamera2Callbacks;
 import androidx.camera.camera2.interop.Camera2Interop;
@@ -102,7 +103,9 @@
     private static final int DEFAULT_AVAILABLE_CAMERA_COUNT = 1;
 
     @Rule
-    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     private final ArrayList<FakeTestUseCase> mFakeTestUseCases = new ArrayList<>();
     private Camera2CameraImpl mCamera2CameraImpl;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ProcessingCaptureSessionTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ProcessingCaptureSessionTest.kt
index a2d476c..e631b70 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ProcessingCaptureSessionTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ProcessingCaptureSessionTest.kt
@@ -32,6 +32,7 @@
 import android.os.SystemClock
 import android.util.Size
 import android.view.Surface
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.internal.compat.CameraManagerCompat
 import androidx.camera.camera2.internal.util.RequestProcessorRequest
 import androidx.camera.camera2.interop.CaptureRequestOptions
@@ -55,6 +56,7 @@
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.testing.CameraUtil
 import androidx.camera.testing.CameraUtil.CameraDeviceHolder
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.concurrent.futures.await
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
@@ -62,6 +64,12 @@
 import androidx.testutils.assertThrows
 import com.google.common.truth.Truth.assertThat
 import com.google.common.util.concurrent.ListenableFuture
+import java.util.Objects
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.Executor
+import java.util.concurrent.ScheduledExecutorService
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.Dispatchers
@@ -75,12 +83,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.Objects
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.ExecutionException
-import java.util.concurrent.Executor
-import java.util.concurrent.ScheduledExecutorService
-import java.util.concurrent.TimeUnit
 
 const val FAKE_CAPTURE_SEQUENCE_ID = 1
 const val JPEG_ORIENTATION_VALUE = 90
@@ -131,7 +133,9 @@
     }
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private lateinit var cameraDeviceHolder: CameraDeviceHolder
     private lateinit var captureSessionRepository: CaptureSessionRepository
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java
index a8c97fa..8143d94 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java
@@ -56,7 +56,9 @@
     private static final int LENS_FACING = CameraSelector.LENS_FACING_BACK;
 
     @Rule
-    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     private TorchControl mTorchControl;
     private CameraUseCaseAdapter mCamera;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.kt
index cfc9f3d..b4b2411 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.kt
@@ -16,21 +16,23 @@
 package androidx.camera.camera2.internal.compat
 
 import android.content.Context
-import androidx.camera.testing.CameraUtil
-import android.hardware.camera2.CameraDevice
 import android.graphics.SurfaceTexture
 import android.hardware.camera2.CameraAccessException
-import android.hardware.camera2.CameraManager
-import androidx.test.core.app.ApplicationProvider
-import android.hardware.camera2.CameraCharacteristics
 import android.hardware.camera2.CameraCaptureSession
+import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraManager
 import android.os.Handler
 import android.os.HandlerThread
 import android.view.Surface
 import androidx.camera.camera2.AsyncCameraDevice
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.internal.compat.params.OutputConfigurationCompat
 import androidx.camera.camera2.internal.compat.params.SessionConfigurationCompat
+import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.core.os.HandlerCompat
+import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
@@ -44,7 +46,6 @@
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers
 import org.mockito.Mockito
-import java.lang.AssertionError
 
 /**
  * Tests some of the methods of [CameraDeviceCompat] on device.
@@ -58,7 +59,9 @@
 @SdkSuppress(minSdkVersion = 21)
 class CameraDeviceCompatDeviceTest {
     @get:Rule
-    var useCamera = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private var cameraDevice: AsyncCameraDevice? = null
     private var surfaceTexture: SurfaceTexture? = null
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerDeviceTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerDeviceTest.kt
index 59cd140..bebdb7a 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerDeviceTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/workaround/ExtraSupportedSurfaceCombinationsContainerDeviceTest.kt
@@ -45,12 +45,16 @@
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.core.internal.CameraUseCaseAdapter
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.CameraXUtil
 import androidx.camera.testing.SurfaceTextureProvider
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
+import java.util.Arrays
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -60,12 +64,8 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.Arrays
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 private const val CAPTURE_TIMEOUT = 10_000.toLong() //  10 seconds
 
@@ -75,7 +75,9 @@
 class ExtraSupportedSurfaceCombinationsContainerDeviceTest(val cameraId: String) {
 
     @get:Rule
-    val useCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
 
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2CameraControlDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2CameraControlDeviceTest.java
index 058be03..7977243 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2CameraControlDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2CameraControlDeviceTest.java
@@ -82,7 +82,9 @@
     private Camera2CameraControlImpl mCamera2CameraControlImpl;
 
     @Rule
-    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     @Before
     public void setUp() {
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java
index 1ff29da..471ab2c 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java
@@ -81,7 +81,9 @@
     private CameraUseCaseAdapter mCamera;
 
     @Rule
-    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     @Before
     public void setUp() {
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/AspectRatioLegacyApi21Quirk.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/AspectRatioLegacyApi21Quirk.java
index 5302a95..7e4c322 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/AspectRatioLegacyApi21Quirk.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/AspectRatioLegacyApi21Quirk.java
@@ -26,13 +26,16 @@
 import androidx.camera.core.impl.Quirk;
 
 /**
- * Quirk that produces stretched use cases on all the legacy API 21 devices.
- *
- * If the device is LEGACY + Android 5.0, then return the same aspect ratio as maximum JPEG
- * resolution. The Camera2 LEGACY mode API always sends the HAL a configure call with the same
- * aspect ratio as the maximum JPEG resolution, and do the cropping/scaling before returning the
- * output. There is a bug because of a flipped scaling factor in the intermediate texture
- * transform matrix, and it was fixed in L MR1. See: b/128924712.
+ * <p>QuirkSummary
+ *     Bug Id: b/128924712
+ *     Description: Quirk that produces stretched use cases on all the legacy API 21 devices. If
+ *     the device is LEGACY + Android 5.0, then return the same aspect ratio as maximum JPEG
+ *     resolution. The Camera2 LEGACY mode API always sends the HAL a configure call with the
+ *     same aspect ratio as the maximum JPEG resolution, and do the cropping/scaling before
+ *     returning the output. There is a bug because of a flipped scaling factor in the
+ *     intermediate texture transform matrix, and it was fixed in L MR1.
+ *     Device(s): All the legacy API 21 devices
+ *     @see androidx.camera.camera2.internal.compat.workaround.TargetAspectRatio
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public class AspectRatioLegacyApi21Quirk implements Quirk {
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/Nexus4AndroidLTargetAspectRatioQuirk.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/Nexus4AndroidLTargetAspectRatioQuirk.java
index 59f3743..7e5499c 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/Nexus4AndroidLTargetAspectRatioQuirk.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/Nexus4AndroidLTargetAspectRatioQuirk.java
@@ -27,11 +27,14 @@
 import java.util.Locale;
 
 /**
- * Quirk that produces stretched preview on Nexus 4 devices running Android L(API levels 21 and 22).
- *
- * <p> There is a Camera1/HAL1 issue on the Nexus 4. The preview will be stretched when
- * configuring a JPEG that doesn't actually have the same aspect ratio as the maximum JPEG
- * resolution. See: b/19606058.
+ * <p>QuirkSummary
+ *     Bug Id: b/19606058
+ *     Description: Quirk that produces stretched preview on Nexus 4 devices running Android L
+ *     (API levels 21 and 22). There is a Camera1/HAL1 issue on the Nexus 4. The preview will be
+ *     stretched when configuring a JPEG that doesn't actually have the same aspect ratio as the
+ *     maximum JPEG resolution.
+ *     Device(s): Google Nexus 4
+ *     @see androidx.camera.camera2.internal.compat.workaround.TargetAspectRatio
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public class Nexus4AndroidLTargetAspectRatioQuirk implements Quirk {
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageProcessingUtilTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageProcessingUtilTest.java
index b30ee814..001238d 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageProcessingUtilTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageProcessingUtilTest.java
@@ -16,11 +16,18 @@
 
 package androidx.camera.core;
 
+import static androidx.camera.core.ImageProcessingUtil.convertJpegBytesToImage;
 import static androidx.camera.core.ImageProcessingUtil.rotateYUV;
 import static androidx.camera.testing.ImageProxyUtil.createYUV420ImagePlanes;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static java.lang.Math.abs;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ImageFormat;
 import android.graphics.PixelFormat;
 import android.media.ImageWriter;
@@ -36,8 +43,12 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.ByteArrayOutputStream;
 import java.nio.ByteBuffer;
 
+/**
+ * Unit test for {@link ImageProcessingUtil}.
+ */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 @SdkSuppress(minSdkVersion = 21)
@@ -50,6 +61,7 @@
     private static final int PIXEL_STRIDE_Y_UNSUPPORTED = 1;
     private static final int PIXEL_STRIDE_UV_UNSUPPORTED = 3;
     private static final int MAX_IMAGES = 4;
+    private static final int JPEG_ENCODE_ERROR_TOLERANCE = 3;
 
     private ByteBuffer mRgbConvertedBuffer;
     private ByteBuffer mYRotatedBuffer;
@@ -60,6 +72,7 @@
     private SafeCloseImageReaderProxy mRGBImageReaderProxy;
     private SafeCloseImageReaderProxy mRotatedRGBImageReaderProxy;
     private SafeCloseImageReaderProxy mRotatedYUVImageReaderProxy;
+    private SafeCloseImageReaderProxy mJpegImageReaderProxy;
 
     @Before
     public void setUp() {
@@ -91,6 +104,13 @@
                         ImageFormat.YUV_420_888,
                         MAX_IMAGES));
 
+        mJpegImageReaderProxy = new SafeCloseImageReaderProxy(
+                ImageReaderProxys.createIsolatedReader(
+                        WIDTH,
+                        HEIGHT,
+                        ImageFormat.JPEG,
+                        MAX_IMAGES));
+
         mRgbConvertedBuffer = ByteBuffer.allocateDirect(WIDTH * HEIGHT * 4);
         mYRotatedBuffer = ByteBuffer.allocateDirect(WIDTH * HEIGHT);
         mURotatedBuffer = ByteBuffer.allocateDirect(WIDTH * HEIGHT / 2);
@@ -104,6 +124,61 @@
     }
 
     @Test
+    public void writeJpeg_returnsTheSameImage() {
+        // Arrange: create a JPEG image with solid color.
+        byte[] inputBytes = createJpegBytesWithSolidColor(Color.RED);
+
+        // Act: acquire image and get the bytes.
+        ImageProxy imageProxy = convertJpegBytesToImage(mJpegImageReaderProxy, inputBytes);
+        assertThat(imageProxy).isNotNull();
+        ByteBuffer byteBuffer = imageProxy.getPlanes()[0].getBuffer();
+        byteBuffer.rewind();
+        byte[] outputBytes = new byte[byteBuffer.capacity()];
+        byteBuffer.get(outputBytes);
+
+        // Assert: the color and the dimension of the restored image.
+        Bitmap bitmap = BitmapFactory.decodeByteArray(outputBytes, 0, outputBytes.length);
+        assertThat(bitmap.getWidth()).isEqualTo(WIDTH);
+        assertThat(bitmap.getHeight()).isEqualTo(HEIGHT);
+        assertBitmapColor(bitmap, Color.RED);
+    }
+
+    /**
+     * Asserts that the given {@link Bitmap} is almost the given color.
+     *
+     * <p>Loops through all the pixels and verify that they are the given color. A small error
+     * is allowed because JPEG is lossy.
+     */
+    private void assertBitmapColor(Bitmap bitmap, int color) {
+        for (int i = 0; i < bitmap.getWidth(); i++) {
+            for (int j = 0; j < bitmap.getHeight(); j++) {
+                int pixelColor = bitmap.getPixel(i, j);
+                // Compare the R, G and B of the pixel to the given color.
+                for (int shift = 16; shift > 0; shift -= 8) {
+                    int pixelRgb = (pixelColor >> shift) & 0xFF;
+                    int rgb = (color >> shift) & 0xFF;
+                    assertThat(abs(pixelRgb - rgb)).isLessThan(JPEG_ENCODE_ERROR_TOLERANCE);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns JPEG bytes of a image with the given color.
+     */
+    private byte[] createJpegBytesWithSolidColor(int color) {
+        Bitmap bitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888);
+        // Draw a solid color
+        Canvas canvas = new Canvas(bitmap);
+        canvas.drawColor(color);
+        canvas.save();
+        // Encode to JPEG and return.
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
+        return stream.toByteArray();
+    }
+
+    @Test
     public void convertYUVToRGBWhenNotFlipUV() {
         // Arrange.
         mYUVImageProxy.setPlanes(createYUV420ImagePlanes(
diff --git a/camera/camera-core/src/main/cpp/image_processing_util_jni.cc b/camera/camera-core/src/main/cpp/image_processing_util_jni.cc
index a8b033e..8e57292 100644
--- a/camera/camera-core/src/main/cpp/image_processing_util_jni.cc
+++ b/camera/camera-core/src/main/cpp/image_processing_util_jni.cc
@@ -132,6 +132,51 @@
     return 0;
 }
 
+/**
+ * Writes the content JPEG array to the Surface.
+ *
+ * <p>This is for wrapping JPEG bytes with a media.Image object.
+ */
+JNIEXPORT jint Java_androidx_camera_core_ImageProcessingUtil_nativeWriteJpegToSurface(
+        JNIEnv *env,
+        jclass,
+        jbyteArray jpeg_array,
+        jobject surface) {
+    ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
+    if (window == nullptr) {
+        LOGE("Failed to get ANativeWindow");
+        return -1;
+    }
+
+    // Updates the size of ANativeWindow_Buffer with the JPEG bytes size.
+    jsize array_size = env->GetArrayLength(jpeg_array);
+    ANativeWindow_setBuffersGeometry(window, array_size, 1, AHARDWAREBUFFER_FORMAT_BLOB);
+
+    ANativeWindow_Buffer buffer;
+    int lockResult = ANativeWindow_lock(window, &buffer, NULL);
+    if (lockResult != 0) {
+        ANativeWindow_release(window);
+        LOGE("Failed to lock window.");
+        return -1;
+    }
+
+    // Copy from source to destination.
+    jbyte *jpeg_ptr = env->GetByteArrayElements(jpeg_array, NULL);
+    if (jpeg_ptr == nullptr) {
+        ANativeWindow_release(window);
+        LOGE("Failed to get JPEG bytes array pointer.");
+        return -1;
+    }
+    uint8_t *buffer_ptr = reinterpret_cast<uint8_t *>(buffer.bits);
+    memcpy(buffer_ptr, jpeg_ptr, array_size);
+
+    ANativeWindow_unlockAndPost(window);
+    ANativeWindow_release(window);
+
+    env->ReleaseByteArrayElements(jpeg_array, jpeg_ptr, 0);
+    return 0;
+}
+
 JNIEXPORT jint Java_androidx_camera_core_ImageProcessingUtil_nativeConvertAndroid420ToABGR(
         JNIEnv* env,
         jclass,
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageProcessingUtil.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageProcessingUtil.java
index f594080..1103c8c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageProcessingUtil.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageProcessingUtil.java
@@ -33,6 +33,7 @@
 import androidx.camera.core.impl.ImageOutputConfig;
 import androidx.camera.core.impl.ImageReaderProxy;
 import androidx.camera.core.internal.compat.ImageWriterCompat;
+import androidx.core.util.Preconditions;
 
 import java.nio.ByteBuffer;
 import java.util.Locale;
@@ -58,16 +59,45 @@
     }
 
     /**
+     * Wraps a JPEG byte array with an {@link Image}.
+     *
+     * <p>This methods wraps the given byte array with an {@link Image} via the help of the
+     * given ImageReader. The image format of the ImageReader has to be JPEG, and the JPEG image
+     * size has to match the size of the ImageReader.
+     */
+    @Nullable
+    public static ImageProxy convertJpegBytesToImage(
+            @NonNull ImageReaderProxy jpegImageReaderProxy,
+            @NonNull byte[] jpegBytes) {
+        Preconditions.checkArgument(jpegImageReaderProxy.getImageFormat() == ImageFormat.JPEG);
+        Preconditions.checkNotNull(jpegBytes);
+
+        Surface surface = jpegImageReaderProxy.getSurface();
+        Preconditions.checkNotNull(surface);
+
+        if (nativeWriteJpegToSurface(jpegBytes, surface) != 0) {
+            Logger.e(TAG, "Failed to enqueue JPEG image.");
+            return null;
+        }
+
+        final ImageProxy imageProxy = jpegImageReaderProxy.acquireLatestImage();
+        if (imageProxy == null) {
+            Logger.e(TAG, "Failed to get acquire JPEG image.");
+        }
+        return imageProxy;
+    }
+
+    /**
      * Converts image proxy in YUV to RGB.
      *
      * Currently this config supports the devices which generated NV21, NV12, I420 YUV layout,
      * otherwise the input YUV layout will be converted to NV12 first and then to RGBA_8888 as a
      * fallback.
      *
-     * @param imageProxy input image proxy in YUV.
-     * @param rgbImageReaderProxy output image reader proxy in RGB.
-     * @param rgbConvertedBuffer intermediate image buffer for format conversion.
-     * @param rotationDegrees output image rotation degrees.
+     * @param imageProxy           input image proxy in YUV.
+     * @param rgbImageReaderProxy  output image reader proxy in RGB.
+     * @param rgbConvertedBuffer   intermediate image buffer for format conversion.
+     * @param rotationDegrees      output image rotation degrees.
      * @param onePixelShiftEnabled true if one pixel shift should be applied, otherwise false.
      * @return output image proxy in RGB.
      */
@@ -152,13 +182,13 @@
     /**
      * Rotates YUV image proxy.
      *
-     * @param imageProxy input image proxy.
+     * @param imageProxy              input image proxy.
      * @param rotatedImageReaderProxy input image reader proxy.
-     * @param rotatedImageWriter output image writer.
-     * @param yRotatedBuffer intermediate image buffer for y plane rotation.
-     * @param uRotatedBuffer intermediate image buffer for u plane rotation.
-     * @param vRotatedBuffer intermediate image buffer for v plane rotation.
-     * @param rotationDegrees output image rotation degrees.
+     * @param rotatedImageWriter      output image writer.
+     * @param yRotatedBuffer          intermediate image buffer for y plane rotation.
+     * @param uRotatedBuffer          intermediate image buffer for u plane rotation.
+     * @param vRotatedBuffer          intermediate image buffer for v plane rotation.
+     * @param rotationDegrees         output image rotation degrees.
      * @return rotated image proxy or null if rotation fails or format is not supported.
      */
     @Nullable
@@ -360,6 +390,9 @@
         return SUCCESS;
     }
 
+    private static native int nativeWriteJpegToSurface(@NonNull byte[] jpegArray,
+            @NonNull Surface surface);
+
     private static native int nativeConvertAndroid420ToABGR(
             @NonNull ByteBuffer srcByteBufferY,
             int srcStrideY,
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java
index 86176ba..ba39474 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java
@@ -29,6 +29,7 @@
 import android.content.Context;
 import android.os.Build;
 
+import androidx.camera.camera2.Camera2Config;
 import androidx.camera.camera2.impl.Camera2ImplConfig;
 import androidx.camera.camera2.impl.CameraEventCallback;
 import androidx.camera.camera2.impl.CameraEventCallbacks;
@@ -65,7 +66,9 @@
 public class ExtensionTest {
 
     @Rule
-    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     @Parameterized.Parameters(name = "effect = {0}, facing = {1}")
     public static Collection<Object[]> getParameters() {
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt
index 7e9dc0d..f0be504 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureTest.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.graphics.SurfaceTexture
 import android.util.Size
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.ImageCapture
 import androidx.camera.core.ImageCaptureException
@@ -28,6 +29,7 @@
 import androidx.camera.extensions.util.ExtensionsTestUtil
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.SurfaceTextureProvider
 import androidx.camera.testing.SurfaceTextureProvider.SurfaceTextureCallback
 import androidx.camera.testing.fakes.FakeLifecycleOwner
@@ -35,6 +37,7 @@
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -48,7 +51,6 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers
 import org.mockito.Mockito
-import java.util.concurrent.TimeUnit
 
 @LargeTest
 @RunWith(Parameterized::class)
@@ -59,7 +61,9 @@
 ) {
 
     @get:Rule
-    val useCamera = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
 
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt
index ec23a83..241e9ab 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewTest.kt
@@ -21,11 +21,13 @@
 import android.os.Handler
 import android.os.HandlerThread
 import android.util.Size
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.Preview
 import androidx.camera.extensions.util.ExtensionsTestUtil
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.GLUtil
 import androidx.camera.testing.SurfaceTextureProvider
 import androidx.camera.testing.fakes.FakeLifecycleOwner
@@ -34,6 +36,8 @@
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -44,8 +48,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 @LargeTest
 @RunWith(Parameterized::class)
@@ -56,7 +58,9 @@
 ) {
 
     @get:Rule
-    val useCamera = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
 
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/ImageCaptureConfigProviderTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/ImageCaptureConfigProviderTest.kt
index 9ffab01..dc7e11a 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/ImageCaptureConfigProviderTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/ImageCaptureConfigProviderTest.kt
@@ -22,6 +22,7 @@
 import android.hardware.camera2.CaptureRequest
 import android.util.Pair
 import android.util.Size
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.interop.Camera2CameraInfo
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.ImageCapture
@@ -32,12 +33,14 @@
 import androidx.camera.extensions.impl.ImageCaptureExtenderImpl
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.fakes.FakeLifecycleOwner
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -53,14 +56,15 @@
 import org.mockito.Mockito.timeout
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
-import java.util.concurrent.TimeUnit
 
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 @SdkSuppress(minSdkVersion = 21)
 class ImageCaptureConfigProviderTest {
     @get:Rule
-    val useCamera = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
 
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/PreviewConfigProviderTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/PreviewConfigProviderTest.kt
index 7b1fbc1..fc1d2f0 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/PreviewConfigProviderTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/internal/PreviewConfigProviderTest.kt
@@ -25,6 +25,7 @@
 import android.media.Image
 import android.util.Pair
 import android.util.Size
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.interop.Camera2CameraInfo
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.Preview
@@ -36,6 +37,7 @@
 import androidx.camera.extensions.impl.RequestUpdateProcessorImpl
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.SurfaceTextureProvider
 import androidx.camera.testing.SurfaceTextureProvider.SurfaceTextureCallback
 import androidx.camera.testing.fakes.FakeLifecycleOwner
@@ -44,6 +46,7 @@
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -61,14 +64,15 @@
 import org.mockito.Mockito.timeout
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
-import java.util.concurrent.TimeUnit
 
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 @SdkSuppress(minSdkVersion = 21)
 class PreviewConfigProviderTest {
     @get:Rule
-    val useCamera = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
 
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
index ca27b15..72a78cf 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/BasicVendorExtender.java
@@ -40,15 +40,12 @@
 import androidx.camera.extensions.impl.BeautyPreviewExtenderImpl;
 import androidx.camera.extensions.impl.BokehImageCaptureExtenderImpl;
 import androidx.camera.extensions.impl.BokehPreviewExtenderImpl;
-import androidx.camera.extensions.impl.CaptureProcessorImpl;
-import androidx.camera.extensions.impl.CaptureStageImpl;
 import androidx.camera.extensions.impl.HdrImageCaptureExtenderImpl;
 import androidx.camera.extensions.impl.HdrPreviewExtenderImpl;
 import androidx.camera.extensions.impl.ImageCaptureExtenderImpl;
 import androidx.camera.extensions.impl.NightImageCaptureExtenderImpl;
 import androidx.camera.extensions.impl.NightPreviewExtenderImpl;
 import androidx.camera.extensions.impl.PreviewExtenderImpl;
-import androidx.camera.extensions.impl.ProcessorImpl;
 import androidx.camera.extensions.internal.compat.workaround.ExtensionDisabledValidator;
 import androidx.core.util.Preconditions;
 
@@ -65,8 +62,8 @@
     private final ExtensionDisabledValidator mExtensionDisabledValidator =
             new ExtensionDisabledValidator();
     private final @ExtensionMode.Mode int mMode;
-    private PreviewExtenderImpl mPreviewExtenderImpl;
-    private ImageCaptureExtenderImpl mImageCaptureExtenderImpl;
+    private PreviewExtenderImpl mPreviewExtenderImpl = null;
+    private ImageCaptureExtenderImpl mImageCaptureExtenderImpl = null;
     private CameraInfo mCameraInfo;
 
     public BasicVendorExtender(@ExtensionMode.Mode int mode) {
@@ -98,26 +95,26 @@
                     throw new IllegalArgumentException("Should not activate ExtensionMode.NONE");
             }
         } catch (NoClassDefFoundError e) {
-            mPreviewExtenderImpl = createDefaultPreviewExtenderImpl();
-            mImageCaptureExtenderImpl = createDefaultImageCaptureExtenderImpl();
             Logger.e(TAG, "OEM implementation for extension mode " + mode + "does not exist!");
         }
     }
 
     /**
-     * Return the {@link PreviewExtenderImpl} instance. This method will be removed once the
-     * existing basic extender implementation is migrated to the unified vendor extender.
+     * Return the {@link PreviewExtenderImpl} instance which could be null if the implementation
+     * doesn't exist. This method will be removed once the existing basic extender implementation
+     * is migrated to the unified vendor extender.
      */
-    @NonNull
+    @Nullable
     public PreviewExtenderImpl getPreviewExtenderImpl() {
         return mPreviewExtenderImpl;
     }
 
     /**
-     * Return the {@link ImageCaptureExtenderImpl} instance. This method will be removed once the
-     * existing basic extender implementation is migrated to the unified vendor extender.
+     * Return the {@link ImageCaptureExtenderImpl} instance which could be null if the
+     * implementation doesn't exist.. This method will be removed once the existing basic
+     * extender implementation is migrated to the unified vendor extender.
      */
-    @NonNull
+    @Nullable
     public ImageCaptureExtenderImpl getImageCaptureExtenderImpl() {
         return mImageCaptureExtenderImpl;
     }
@@ -130,6 +127,11 @@
             return false;
         }
 
+        // Returns false if implementation classes do not exist.
+        if (mPreviewExtenderImpl == null || mImageCaptureExtenderImpl == null) {
+            return false;
+        }
+
         CameraCharacteristics cameraCharacteristics = characteristicsMap.get(cameraId);
         return mPreviewExtenderImpl.isExtensionAvailable(cameraId, cameraCharacteristics)
                 && mImageCaptureExtenderImpl.isExtensionAvailable(cameraId, cameraCharacteristics);
@@ -139,6 +141,11 @@
     @Override
     public void init(@NonNull CameraInfo cameraInfo) {
         mCameraInfo = cameraInfo;
+
+        if (mPreviewExtenderImpl == null || mImageCaptureExtenderImpl == null) {
+            return;
+        }
+
         String cameraId = Camera2CameraInfo.from(cameraInfo).getCameraId();
         CameraCharacteristics cameraCharacteristics =
                 Camera2CameraInfo.extractCameraCharacteristics(cameraInfo);
@@ -155,7 +162,8 @@
     @Override
     public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size size) {
         Preconditions.checkNotNull(mCameraInfo, "VendorExtender#init() must be called first");
-        if (ExtensionVersion.getRuntimeVersion().compareTo(Version.VERSION_1_2) >= 0) {
+        if (mImageCaptureExtenderImpl != null && ExtensionVersion.getRuntimeVersion().compareTo(
+                Version.VERSION_1_2) >= 0) {
             try {
                 return mImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange(size);
             } catch (NoSuchMethodError e) {
@@ -173,7 +181,7 @@
     }
 
     private int getPreviewInputImageFormat() {
-        if (mPreviewExtenderImpl.getProcessorType()
+        if (mPreviewExtenderImpl != null && mPreviewExtenderImpl.getProcessorType()
                 == PreviewExtenderImpl.ProcessorType.PROCESSOR_TYPE_IMAGE_PROCESSOR) {
             return ImageFormat.YUV_420_888;
         } else {
@@ -182,7 +190,8 @@
     }
 
     private int getCaptureInputImageFormat() {
-        if (mImageCaptureExtenderImpl.getCaptureProcessor() != null) {
+        if (mImageCaptureExtenderImpl != null
+                && mImageCaptureExtenderImpl.getCaptureProcessor() != null) {
             return ImageFormat.YUV_420_888;
         } else {
             return ImageFormat.JPEG;
@@ -194,7 +203,8 @@
     public List<Pair<Integer, Size[]>> getSupportedPreviewOutputResolutions() {
         Preconditions.checkNotNull(mCameraInfo, "VendorExtender#init() must be called first");
 
-        if (ExtensionVersion.getRuntimeVersion().compareTo(Version.VERSION_1_1) >= 0) {
+        if (mPreviewExtenderImpl != null && ExtensionVersion.getRuntimeVersion().compareTo(
+                Version.VERSION_1_1) >= 0) {
             try {
                 List<Pair<Integer, Size[]>> result =
                         mPreviewExtenderImpl.getSupportedResolutions();
@@ -217,7 +227,8 @@
     @Override
     public List<Pair<Integer, Size[]>> getSupportedCaptureOutputResolutions() {
         Preconditions.checkNotNull(mCameraInfo, "VendorExtender#init() must be called first");
-        if (ExtensionVersion.getRuntimeVersion().compareTo(Version.VERSION_1_1) >= 0) {
+        if (mImageCaptureExtenderImpl != null && ExtensionVersion.getRuntimeVersion().compareTo(
+                Version.VERSION_1_1) >= 0) {
             try {
                 List<Pair<Integer, Size[]>> result =
                         mImageCaptureExtenderImpl.getSupportedResolutions();
@@ -251,134 +262,4 @@
          */
         return null;
     }
-
-    private PreviewExtenderImpl createDefaultPreviewExtenderImpl() {
-        return new PreviewExtenderImpl() {
-            @Override
-            public boolean isExtensionAvailable(String cameraId,
-                    CameraCharacteristics cameraCharacteristics) {
-                return false;
-            }
-
-            @Override
-            public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
-
-            }
-
-            @Override
-            public CaptureStageImpl getCaptureStage() {
-                return null;
-            }
-
-            @Override
-            public ProcessorType getProcessorType() {
-                return ProcessorType.PROCESSOR_TYPE_NONE;
-            }
-
-            @Override
-            public ProcessorImpl getProcessor() {
-                return null;
-            }
-
-            @Nullable
-            @Override
-            public List<Pair<Integer, Size[]>> getSupportedResolutions() {
-                return null;
-            }
-
-            @Override
-            public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-                    Context context) {
-
-            }
-
-            @Override
-            public void onDeInit() {
-
-            }
-
-            @Override
-            public CaptureStageImpl onPresetSession() {
-                return null;
-            }
-
-            @Override
-            public CaptureStageImpl onEnableSession() {
-                return null;
-            }
-
-            @Override
-            public CaptureStageImpl onDisableSession() {
-                return null;
-            }
-        };
-    }
-
-    private ImageCaptureExtenderImpl createDefaultImageCaptureExtenderImpl() {
-        return new ImageCaptureExtenderImpl() {
-            @Override
-            public boolean isExtensionAvailable(String cameraId,
-                    CameraCharacteristics cameraCharacteristics) {
-                return false;
-            }
-
-            @Override
-            public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
-
-            }
-
-            @Override
-            public CaptureProcessorImpl getCaptureProcessor() {
-                return null;
-            }
-
-            @Override
-            public List<CaptureStageImpl> getCaptureStages() {
-                return null;
-            }
-
-            @Override
-            public int getMaxCaptureStage() {
-                return 0;
-            }
-
-            @Nullable
-            @Override
-            public List<Pair<Integer, Size[]>> getSupportedResolutions() {
-                return null;
-            }
-
-            @Nullable
-            @Override
-            public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
-                return null;
-            }
-
-            @Override
-            public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-                    Context context) {
-
-            }
-
-            @Override
-            public void onDeInit() {
-
-            }
-
-            @Override
-            public CaptureStageImpl onPresetSession() {
-                return null;
-            }
-
-            @Override
-            public CaptureStageImpl onEnableSession() {
-                return null;
-            }
-
-            @Override
-            public CaptureStageImpl onDisableSession() {
-                return null;
-            }
-        };
-    }
 }
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java
index d3a3bea..c280363 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/ImageCaptureConfigProvider.java
@@ -95,25 +95,29 @@
             ImageCaptureExtenderImpl imageCaptureExtenderImpl =
                     ((BasicVendorExtender) vendorExtender).getImageCaptureExtenderImpl();
 
-            CaptureProcessorImpl captureProcessor =
-                    imageCaptureExtenderImpl.getCaptureProcessor();
-            if (captureProcessor != null) {
-                builder.setCaptureProcessor(new AdaptingCaptureProcessor(captureProcessor));
+            if (imageCaptureExtenderImpl != null) {
+                CaptureProcessorImpl captureProcessor =
+                        imageCaptureExtenderImpl.getCaptureProcessor();
+                if (captureProcessor != null) {
+                    builder.setCaptureProcessor(new AdaptingCaptureProcessor(captureProcessor));
+                }
+
+                if (imageCaptureExtenderImpl.getMaxCaptureStage() > 0) {
+                    builder.setMaxCaptureStages(
+                            imageCaptureExtenderImpl.getMaxCaptureStage());
+                }
+
+                ImageCaptureEventAdapter imageCaptureEventAdapter =
+                        new ImageCaptureEventAdapter(imageCaptureExtenderImpl,
+                                context);
+                new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback(
+                        new CameraEventCallbacks(imageCaptureEventAdapter));
+                builder.setUseCaseEventCallback(imageCaptureEventAdapter);
+
+                builder.setCaptureBundle(imageCaptureEventAdapter);
+            } else {
+                Logger.e(TAG, "ImageCaptureExtenderImpl is null!");
             }
-
-            if (imageCaptureExtenderImpl.getMaxCaptureStage() > 0) {
-                builder.setMaxCaptureStages(
-                        imageCaptureExtenderImpl.getMaxCaptureStage());
-            }
-
-            ImageCaptureEventAdapter imageCaptureEventAdapter =
-                    new ImageCaptureEventAdapter(imageCaptureExtenderImpl,
-                            context);
-            new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback(
-                    new CameraEventCallbacks(imageCaptureEventAdapter));
-            builder.setUseCaseEventCallback(imageCaptureEventAdapter);
-
-            builder.setCaptureBundle(imageCaptureEventAdapter);
         }
 
         builder.getMutableConfig().insertOption(OPTION_IMAGE_CAPTURE_CONFIG_PROVIDER_MODE,
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java
index 14e3138a..3da8a12 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/internal/PreviewConfigProvider.java
@@ -86,34 +86,39 @@
             @ExtensionMode.Mode int effectMode, @NonNull VendorExtender vendorExtender,
             @NonNull Context context) {
         if (vendorExtender instanceof BasicVendorExtender) {
-            PreviewEventAdapter previewEventAdapter;
             PreviewExtenderImpl previewExtenderImpl =
                     ((BasicVendorExtender) vendorExtender).getPreviewExtenderImpl();
-            switch (previewExtenderImpl.getProcessorType()) {
-                case PROCESSOR_TYPE_REQUEST_UPDATE_ONLY:
-                    AdaptingRequestUpdateProcessor adaptingRequestUpdateProcessor =
-                            new AdaptingRequestUpdateProcessor(previewExtenderImpl);
-                    builder.setImageInfoProcessor(adaptingRequestUpdateProcessor);
-                    previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
-                            adaptingRequestUpdateProcessor);
-                    break;
-                case PROCESSOR_TYPE_IMAGE_PROCESSOR:
-                    AdaptingPreviewProcessor adaptingPreviewProcessor = new
-                            AdaptingPreviewProcessor(
-                            (PreviewImageProcessorImpl) previewExtenderImpl.getProcessor());
-                    builder.setCaptureProcessor(adaptingPreviewProcessor);
-                    previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
-                            adaptingPreviewProcessor);
-                    break;
-                default:
-                    previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
-                            null);
-            }
-            new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback(
-                    new CameraEventCallbacks(previewEventAdapter));
-            builder.setUseCaseEventCallback(previewEventAdapter);
-        }
 
+            if (previewExtenderImpl != null) {
+                PreviewEventAdapter previewEventAdapter;
+
+                switch (previewExtenderImpl.getProcessorType()) {
+                    case PROCESSOR_TYPE_REQUEST_UPDATE_ONLY:
+                        AdaptingRequestUpdateProcessor adaptingRequestUpdateProcessor =
+                                new AdaptingRequestUpdateProcessor(previewExtenderImpl);
+                        builder.setImageInfoProcessor(adaptingRequestUpdateProcessor);
+                        previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
+                                adaptingRequestUpdateProcessor);
+                        break;
+                    case PROCESSOR_TYPE_IMAGE_PROCESSOR:
+                        AdaptingPreviewProcessor adaptingPreviewProcessor = new
+                                AdaptingPreviewProcessor(
+                                (PreviewImageProcessorImpl) previewExtenderImpl.getProcessor());
+                        builder.setCaptureProcessor(adaptingPreviewProcessor);
+                        previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
+                                adaptingPreviewProcessor);
+                        break;
+                    default:
+                        previewEventAdapter = new PreviewEventAdapter(previewExtenderImpl, context,
+                                null);
+                }
+                new Camera2ImplConfig.Extender<>(builder).setCameraEventCallback(
+                        new CameraEventCallbacks(previewEventAdapter));
+                builder.setUseCaseEventCallback(previewEventAdapter);
+            } else {
+                Logger.e(TAG, "PreviewExtenderImpl is null!");
+            }
+        }
 
         builder.getMutableConfig().insertOption(OPTION_PREVIEW_CONFIG_PROVIDER_MODE, effectMode);
         List<Pair<Integer, Size[]>> supportedResolutions =
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java b/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
index f14b686..a16c209 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
@@ -23,6 +23,7 @@
 import android.Manifest;
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
@@ -700,63 +701,77 @@
     }
 
     /**
-     * Create a chained rule for the test cases that need to use the camera.
+     * Grant the camera permission and test the camera.
      *
      * <p>It will
      * (1) Grant the camera permission.
-     * (2) Check if there is at least one camera on the device.
-     * (3) Test the camera can be opened successfully.
-     *
-     * <p>This method will set {@link PreTestCamera} to throw an exception when the camera is
-     * unavailable if PRETEST_CAMERA_TAG is loggable at the debug level (see Log#isLoggable).
+     * (2) Check if there is at least one camera on the device alive. If not, it will ignore
+     * the test.
+     * (3) Ensure the camera can be opened successfully before the test. If not, it will ignore
+     * the test.
      */
     @NonNull
     public static TestRule grantCameraPermissionAndPreTest() {
-        return grantCameraPermissionAndPreTest(new PreTestCamera());
+        return grantCameraPermissionAndPreTest(new PreTestCamera(), new PreTestCameraIdList());
     }
 
     /**
      * Grant the camera permission and test the camera.
      *
-     * @param cameraTestRule the PreTestCamera rule to execute the camera test.
+     * <p>This method is mainly required to be used when running the test with
+     * Camera2Config/CameraPipeConfig. Please create a PreTestCameraIdList with the CameraXConfig
+     * that is used in the test.
+     * If the test uses fake CameraXConfig or doesn't initialize CameraX, i.e. doesn't uses
+     * {@link androidx.camera.lifecycle.ProcessCameraProvider} or {@link CameraXUtil#initialize} to
+     * initialize CameraX for testing, you can use
+     * {@link CameraUtil#grantCameraPermissionAndPreTest()} instead.
      */
     @NonNull
-    public static TestRule grantCameraPermissionAndPreTest(@NonNull PreTestCamera cameraTestRule) {
-        RuleChain rule =
-                RuleChain.outerRule(GrantPermissionRule.grant(Manifest.permission.CAMERA)).around(
-                        (base, description) -> new Statement() {
-                            @Override
-                            public void evaluate() throws Throwable {
-                                dumpCameraLensFacingInfo();
-                                assumeTrue(deviceHasCamera());
-                                base.evaluate();
-                            }
-                        }).around(cameraTestRule);
+    public static TestRule grantCameraPermissionAndPreTest(
+            @Nullable PreTestCameraIdList cameraIdListTestRule) {
+        return grantCameraPermissionAndPreTest(new PreTestCamera(), cameraIdListTestRule);
+    }
+
+    /**
+     * Grant the camera permission and test the camera.
+     *
+     * @param cameraTestRule       to check if camera can be opened.
+     * @param cameraIdListTestRule to check if camera characteristic reports correct information
+     *                             that includes the supported camera devices that shows in the
+     *                             system.
+     */
+    @NonNull
+    public static TestRule grantCameraPermissionAndPreTest(@Nullable PreTestCamera cameraTestRule,
+            @Nullable PreTestCameraIdList cameraIdListTestRule) {
+        RuleChain rule = RuleChain.outerRule(GrantPermissionRule.grant(Manifest.permission.CAMERA));
+        if (cameraIdListTestRule != null) {
+            rule = rule.around(cameraIdListTestRule);
+        }
+        if (cameraTestRule != null) {
+            rule = rule.around(cameraTestRule);
+        }
+        rule = rule.around((base, description) -> new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                assumeTrue(deviceHasCamera());
+                base.evaluate();
+            }
+        });
+
         return rule;
     }
 
     /**
-     * Pretest the camera device
+     * Test the camera device
      *
-     * <p>Try to open the camera with the front and back lensFacing. It throws exception when
-     * camera is unavailable and mThrowOnError is true.
-     *
-     * <p>Passing false into the constructor {@link #PreTestCamera(boolean)}
-     * will never throw the exception when the camera is unavailable.
+     * <p>Try to open the camera with the front and back lensFacing. It throws an exception when
+     * the test is running in the CameraX lab, or ignore the test otherwise.
      */
     @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
     public static class PreTestCamera implements TestRule {
-        final boolean mThrowOnError;
+        final boolean mThrowOnError = Log.isLoggable(PRETEST_CAMERA_TAG, Log.DEBUG);
         final AtomicReference<Boolean> mCanOpenCamera = new AtomicReference<>();
 
-        public PreTestCamera() {
-            mThrowOnError = Log.isLoggable(PRETEST_CAMERA_TAG, Log.DEBUG);
-        }
-
-        public PreTestCamera(boolean throwOnError) {
-            mThrowOnError = throwOnError;
-        }
-
         @NonNull
         @Override
         public Statement apply(@NonNull Statement base, @NonNull Description description) {
@@ -784,7 +799,7 @@
                         mCanOpenCamera.set(backStatus && frontStatus);
                     }
 
-                    if (mCanOpenCamera.get()) {
+                    if (Boolean.TRUE.equals(mCanOpenCamera.get())) {
                         base.evaluate();
                     } else {
                         if (mThrowOnError) {
@@ -983,17 +998,92 @@
     }
 
     /**
-     * Log the camera lensFacing info for b/167201193 debug.
-     * Throw exception with a specific message if the Camera doesn't have both front/back lens
-     * facing in the daily testing.
+     * Check the camera lensFacing info is reported correctly
+     *
+     * <p>For b/167201193
+     *
+     * <P>Try to use the CameraXConfig to initialize CameraX when it fails to detect the valid
+     * lens facing info from camera characteristics. It throws an exception if it cannot
+     * successfully init CameraX (or throws AssumptionViolatedException when it is not in the
+     * CameraX lab).
+     */
+    public static class PreTestCameraIdList implements TestRule {
+        final boolean mThrowOnError = Log.isLoggable("CameraXDumpIdList", Log.DEBUG);
+        final AtomicReference<Boolean> mCameraIdListCorrect = new AtomicReference<>();
+
+        @Nullable
+        final CameraXConfig mCameraXConfig;
+
+        public PreTestCameraIdList() {
+            mCameraXConfig = null;
+        }
+
+        /**
+         * Try to use the {@link CameraXConfig} to initialize CameraX when it fails to detect the
+         * valid lens facing info from camera characteristics.
+         */
+        public PreTestCameraIdList(@NonNull CameraXConfig config) {
+            mCameraXConfig = config;
+        }
+
+        @NonNull
+        @Override
+        public Statement apply(@NonNull Statement base, @NonNull Description description) {
+            return new Statement() {
+                @Override
+                public void evaluate() throws Throwable {
+                    if (mCameraIdListCorrect.get() == null) {
+                        if (isCameraLensFacingInfoAvailable()) {
+                            mCameraIdListCorrect.set(true);
+                        } else if (mCameraXConfig != null) {
+                            try {
+                                CameraXUtil.initialize(ApplicationProvider.getApplicationContext(),
+                                        mCameraXConfig).get(10, TimeUnit.SECONDS);
+                                Logger.i(LOG_TAG, "Successfully init CameraX");
+                                mCameraIdListCorrect.set(true);
+                            } catch (Exception e) {
+                                Logger.w(LOG_TAG, "CameraX init fail");
+                                mCameraIdListCorrect.set(false);
+                            } finally {
+                                try {
+                                    CameraXUtil.shutdown().get(10, TimeUnit.SECONDS);
+                                } catch (Exception e) {
+                                    // Ignore all exceptions in the shutdown process.
+                                }
+                            }
+                        } else {
+                            mCameraIdListCorrect.set(false);
+                        }
+                    }
+
+                    if (Boolean.TRUE.equals(mCameraIdListCorrect.get())) {
+                        base.evaluate();
+                    } else {
+                        if (mThrowOnError) {
+                            throw new IllegalArgumentException(
+                                    "CameraIdList_incorrect:" + Build.MODEL);
+                        }
+
+                        // Ignore the test, throw the AssumptionViolatedException.
+                        throw new AssumptionViolatedException("Ignore the test since the camera "
+                                + "id list failed, on test " + description.getDisplayName());
+                    }
+                }
+            };
+        }
+    }
+
+    /**
+     * Check the camera lensFacing info for b/167201193 debug.
+     *
+     * @return true if the front and main camera info exists in the camera characteristic.
      */
     @SuppressWarnings("ObjectToString")
-    static void dumpCameraLensFacingInfo() {
+    static boolean isCameraLensFacingInfoAvailable() {
         boolean error = false;
+        Context context = ApplicationProvider.getApplicationContext();
+        CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
 
-        CameraManager manager =
-                (CameraManager) ApplicationProvider.getApplicationContext().getSystemService(
-                        Context.CAMERA_SERVICE);
         String[] cameraIds = new String[0];
         try {
             cameraIds = manager.getCameraIdList();
@@ -1004,7 +1094,6 @@
         }
 
         if (cameraIds != null && cameraIds.length > 0) {
-            List<String> ids = Arrays.asList(cameraIds);
             boolean hasFront = false;
             boolean hasBack = false;
             for (String id : cameraIds) {
@@ -1028,25 +1117,27 @@
                 Logger.d(LOG_TAG, "-- Camera id: " + id);
             }
 
-            if (!ids.contains("0") || !ids.contains("1")) {
+            PackageManager pm = context.getPackageManager();
+            boolean backFeature = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
+            boolean frontFeature = pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
+
+            // Pass when no such feature or it gets the camera from the camera characteristic.
+            boolean backPass = !backFeature || hasBack;
+            boolean frontPass = !frontFeature || hasFront;
+
+            if (!backPass || !frontPass) {
                 error = true;
                 Logger.e(LOG_TAG,
-                        "Camera Id 0 or 1 is missing,  ids: " + Arrays.toString(cameraIds));
-            }
-
-            if (!hasFront || !hasBack) {
-                Logger.e(LOG_TAG,
                         "Missing front or back camera, has front camera: " + hasFront + ", has "
-                                + "back camera: " + hasBack);
+                                + "back camera: " + hasBack + " has main camera feature:"
+                                + backFeature + " has front camera feature:" + frontFeature
+                                + " ids: " + Arrays.toString(cameraIds));
             }
         } else {
             error = true;
             Logger.e(LOG_TAG, "cameraIds.length is zero");
         }
 
-        if (error && Log.isLoggable("CameraXDumpIdList", Log.DEBUG)) {
-            throw new IllegalArgumentException("CameraIdList_incorrect:" + Build.MODEL);
-        }
-
+        return !error;
     }
 }
\ No newline at end of file
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt
index 0acdac5..60223dc 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/RecorderTest.kt
@@ -76,7 +76,6 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.TestName
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.any
@@ -98,7 +97,9 @@
 class RecorderTest {
 
     @get:Rule
-    var cameraRule: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     var testName: TestName = TestName()
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/SupportedQualitiesVerificationTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/SupportedQualitiesVerificationTest.kt
index a9a76e3..c29dc5c 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/SupportedQualitiesVerificationTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/SupportedQualitiesVerificationTest.kt
@@ -34,6 +34,7 @@
 
 import android.content.Context
 import android.os.Build
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.Camera
 import androidx.camera.core.CameraInfo
 import androidx.camera.core.CameraSelector
@@ -67,7 +68,9 @@
 ) {
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     companion object {
         private const val VIDEO_TIMEOUT_SEC = 10L
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoCaptureDeviceTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoCaptureDeviceTest.kt
index e29939a..83d3697 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoCaptureDeviceTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoCaptureDeviceTest.kt
@@ -37,6 +37,10 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import java.util.concurrent.ArrayBlockingQueue
+import java.util.concurrent.Executors
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -47,10 +51,6 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import java.util.concurrent.ArrayBlockingQueue
-import java.util.concurrent.Executors
-import java.util.concurrent.Semaphore
-import java.util.concurrent.TimeUnit
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
@@ -58,7 +58,9 @@
 class VideoCaptureDeviceTest {
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
     private val context: Context = ApplicationProvider.getApplicationContext()
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingFrameDropTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingFrameDropTest.kt
index 8fa45e5..3fb0fb8d 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingFrameDropTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingFrameDropTest.kt
@@ -23,6 +23,7 @@
 import android.hardware.camera2.CaptureRequest
 import android.os.Build
 import android.view.Surface
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.interop.Camera2CameraInfo
 import androidx.camera.camera2.interop.Camera2Interop
 import androidx.camera.core.AspectRatio
@@ -56,7 +57,6 @@
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.SharedFlow
 import kotlinx.coroutines.flow.asSharedFlow
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.takeWhile
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
@@ -67,7 +67,6 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 
@@ -83,7 +82,9 @@
     private val perSelectorTestData: PerSelectorTestData
 ) {
     @get:Rule
-    var cameraRule: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     // Due to the flaky nature of this test, it should only be run in the lab
     @get:Rule
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt
index 76f75a3..cdad492 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoRecordingTest.kt
@@ -25,6 +25,7 @@
 import android.util.Log
 import android.util.Size
 import android.view.Surface
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.Camera
 import androidx.camera.core.CameraInfo
 import androidx.camera.core.CameraSelector
@@ -76,7 +77,9 @@
 ) {
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val permissionRule: GrantPermissionRule =
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/encoder/VideoEncoderTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/encoder/VideoEncoderTest.kt
index ca8de01..57cbb30 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/encoder/VideoEncoderTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/encoder/VideoEncoderTest.kt
@@ -60,7 +60,6 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.any
@@ -84,8 +83,10 @@
 @SdkSuppress(minSdkVersion = 21)
 class VideoEncoderTest {
 
-    @get: Rule
-    var cameraRule: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    @get:Rule
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
     private val context: Context = ApplicationProvider.getApplicationContext()
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt
index 6c34d8d..9a2d3db 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/workaround/EncoderFinderTest.kt
@@ -56,7 +56,9 @@
 ) {
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val labTest: LabTestRule = LabTestRule()
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt b/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
index 94d3653..9acd91c 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
@@ -18,12 +18,14 @@
 
 import android.content.ContentValues
 import android.provider.MediaStore
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.CameraSelector.LENS_FACING_BACK
 import androidx.camera.core.CameraSelector.LENS_FACING_FRONT
 import androidx.camera.core.ImageCapture
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.fakes.FakeLifecycleOwner
 import androidx.test.annotation.UiThreadTest
 import androidx.test.core.app.ApplicationProvider
@@ -32,14 +34,13 @@
 import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.TimeUnit
 import org.junit.After
 import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
-import java.util.concurrent.TimeUnit
 
 /**
  * Instrumentation tests for [CameraController].
@@ -50,7 +51,9 @@
 class CameraControllerDeviceTest {
 
     @get:Rule
-    val useCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val controller = LifecycleCameraController(ApplicationProvider.getApplicationContext())
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewBitmapTest.java b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewBitmapTest.java
index 285c7f3..162a8e7 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewBitmapTest.java
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewBitmapTest.java
@@ -22,6 +22,7 @@
 import android.graphics.Bitmap;
 
 import androidx.annotation.NonNull;
+import androidx.camera.camera2.Camera2Config;
 import androidx.camera.core.CameraSelector;
 import androidx.camera.core.Preview;
 import androidx.camera.lifecycle.ProcessCameraProvider;
@@ -62,7 +63,9 @@
             FakeActivity.class);
 
     @Rule
-    public final TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     private static final int CAMERA_LENS = CameraSelector.LENS_FACING_BACK;
     private ProcessCameraProvider mCameraProvider;
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewDeviceTest.kt b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewDeviceTest.kt
index 8f54585..0e93506 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewDeviceTest.kt
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewDeviceTest.kt
@@ -29,6 +29,7 @@
 import android.view.TextureView
 import android.view.View
 import android.widget.FrameLayout
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.Camera
 import androidx.camera.core.CameraInfo
 import androidx.camera.core.CameraSelector
@@ -43,6 +44,7 @@
 import androidx.camera.core.impl.utils.futures.Futures
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.CoreAppTestUtil
 import androidx.camera.testing.CoreAppTestUtil.ForegroundOccupiedError
 import androidx.camera.testing.SurfaceFormatUtil
@@ -66,6 +68,12 @@
 import androidx.test.uiautomator.UiSelector
 import com.google.common.truth.Truth
 import com.google.common.util.concurrent.ListenableFuture
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeoutException
+import java.util.concurrent.atomic.AtomicReference
 import org.junit.After
 import org.junit.Assume
 import org.junit.Before
@@ -73,12 +81,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.ExecutionException
-import java.util.concurrent.Semaphore
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.TimeoutException
-import java.util.concurrent.atomic.AtomicReference
 
 /**
  * Instrumented tests for [PreviewView].
@@ -88,7 +90,9 @@
 @SdkSuppress(minSdkVersion = 21)
 class PreviewViewDeviceTest {
     @get:Rule
-    var useCamera = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
     private var activityScenario: ActivityScenario<FakeActivity>? = null
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewStreamStateTest.kt b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewStreamStateTest.kt
index effaf39..d59f07a 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewStreamStateTest.kt
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewStreamStateTest.kt
@@ -17,11 +17,13 @@
 package androidx.camera.view
 
 import android.content.Context
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.ImageAnalysis
 import androidx.camera.core.Preview
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.CoreAppTestUtil
 import androidx.camera.testing.fakes.FakeActivity
 import androidx.camera.testing.fakes.FakeLifecycleOwner
@@ -33,17 +35,16 @@
 import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import org.junit.After
 import org.junit.Assume
 import org.junit.Before
 import org.junit.BeforeClass
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 @LargeTest
 @RunWith(Parameterized::class)
@@ -74,7 +75,9 @@
     private lateinit var mCameraProvider: ProcessCameraProvider
 
     @get:Rule
-    val mUseCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val mActivityRule: ActivityScenarioRule<FakeActivity> =
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/BasicUITest.java b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/BasicUITest.java
index 70f90bf..aefea06 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/BasicUITest.java
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/BasicUITest.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.Intent;
 
+import androidx.camera.camera2.Camera2Config;
 import androidx.camera.core.ImageAnalysis;
 import androidx.camera.core.Preview;
 import androidx.camera.testing.CameraUtil;
@@ -67,7 +68,9 @@
             new ActivityTestRule<>(CameraXActivity.class, true, false);
 
     @Rule
-    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     @Rule
     public GrantPermissionRule mStoragePermissionRule =
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/Camera2InteropIntegrationTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/Camera2InteropIntegrationTest.kt
index 84eccda..c444306 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/Camera2InteropIntegrationTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/Camera2InteropIntegrationTest.kt
@@ -27,6 +27,7 @@
 import android.hardware.camera2.CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
 import android.hardware.camera2.CaptureRequest
 import android.hardware.camera2.TotalCaptureResult
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.interop.Camera2CameraControl
 import androidx.camera.camera2.interop.Camera2CameraInfo
 import androidx.camera.camera2.interop.Camera2Interop
@@ -38,6 +39,7 @@
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.concurrent.futures.await
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.LifecycleOwner
@@ -46,6 +48,8 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -60,17 +64,16 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
 class Camera2InteropIntegrationTest {
 
     @get:Rule
-    val useCameraRule: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private var processCameraProvider: ProcessCameraProvider? = null
 
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CameraDisconnectTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CameraDisconnectTest.kt
index c7b1753..44d8215 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CameraDisconnectTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/CameraDisconnectTest.kt
@@ -25,6 +25,7 @@
 import androidx.camera.core.CameraXConfig
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.CoreAppTestUtil
 import androidx.camera.testing.activity.Camera2TestActivity
 import androidx.camera.testing.activity.CameraXTestActivity
@@ -37,13 +38,13 @@
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
+import java.util.concurrent.TimeUnit
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.TimeUnit
 
 /** Tests for [CameraX] which varies use case combinations to run. */
 @LargeTest
@@ -54,7 +55,9 @@
 ) {
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(cameraConfig)
+    )
 
     companion object {
         @JvmStatic
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ExistingActivityLifecycleTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ExistingActivityLifecycleTest.kt
index 1414e30..e84c886 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ExistingActivityLifecycleTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ExistingActivityLifecycleTest.kt
@@ -19,9 +19,11 @@
 import android.app.Instrumentation
 import android.content.Context
 import android.os.Build
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.CameraSelector
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.CoreAppTestUtil
 import androidx.lifecycle.Lifecycle.State.CREATED
 import androidx.lifecycle.Lifecycle.State.RESUMED
@@ -37,6 +39,7 @@
 import androidx.test.uiautomator.UiDevice
 import androidx.testutils.RepeatRule
 import androidx.testutils.withActivity
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.runBlocking
 import org.junit.After
 import org.junit.AfterClass
@@ -44,9 +47,7 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
-import java.util.concurrent.TimeUnit
 
 private const val HOME_TIMEOUT_MS = 3000L
 private const val ROTATE_TIMEOUT_MS = 2000L
@@ -59,7 +60,9 @@
         UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
 
     @get:Rule
-    val mUseCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val mPermissionRule: GrantPermissionRule =
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt
index 9c8383c..f643280 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/FlashTest.kt
@@ -29,12 +29,15 @@
 import androidx.camera.core.Preview
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.LabTestRule
 import androidx.camera.testing.SurfaceTextureProvider
 import androidx.camera.testing.fakes.FakeLifecycleOwner
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
 import com.google.common.truth.Truth
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.delay
@@ -47,8 +50,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 private val BACK_SELECTOR = CameraSelector.DEFAULT_BACK_CAMERA
 private const val BACK_LENS_FACING = CameraSelector.LENS_FACING_BACK
@@ -59,7 +60,9 @@
 class FlashTest(private val implName: String, private val cameraXConfig: CameraXConfig) {
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(cameraXConfig)
+    )
 
     @get:Rule
     val labTest: LabTestRule = LabTestRule()
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageAnalysisTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageAnalysisTest.kt
index cc54f36..b713dbc 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageAnalysisTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageAnalysisTest.kt
@@ -34,11 +34,14 @@
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.LabTestRule
 import androidx.camera.testing.fakes.FakeLifecycleOwner
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -49,8 +52,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.Semaphore
-import java.util.concurrent.TimeUnit
 
 private val DEFAULT_CAMERA_SELECTOR = CameraSelector.DEFAULT_BACK_CAMERA
 
@@ -62,7 +63,9 @@
 ) {
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(cameraConfig)
+    )
 
     @get:Rule
     val labTest: LabTestRule = LabTestRule()
@@ -120,7 +123,9 @@
             }
         }
 
-        handlerThread.quitSafely()
+        if (::handler.isInitialized) {
+            handlerThread.quitSafely()
+        }
     }
 
     @Test
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
index 9f207ab..b06614e 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureTest.kt
@@ -67,6 +67,13 @@
 import androidx.test.filters.SdkSuppress
 import androidx.test.rule.GrantPermissionRule
 import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayInputStream
+import java.io.File
+import java.io.FileOutputStream
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicInteger
+import kotlin.math.abs
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
@@ -81,13 +88,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.io.ByteArrayInputStream
-import java.io.File
-import java.io.FileOutputStream
-import java.util.concurrent.ExecutionException
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.atomic.AtomicInteger
-import kotlin.math.abs
 
 private val DEFAULT_RESOLUTION = Size(640, 480)
 private val BACK_SELECTOR = CameraSelector.DEFAULT_BACK_CAMERA
@@ -99,7 +99,9 @@
 class ImageCaptureTest(private val implName: String, private val cameraXConfig: CameraXConfig) {
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(cameraXConfig)
+    )
 
     @get:Rule
     val externalStorageRule: GrantPermissionRule =
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageProcessingLatencyTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageProcessingLatencyTest.kt
index e0a6b31..157c379 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageProcessingLatencyTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageProcessingLatencyTest.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.util.Size
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.ImageAnalysis
 import androidx.camera.core.ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888
@@ -29,6 +30,8 @@
 import androidx.camera.testing.fakes.FakeLifecycleOwner
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.runBlocking
@@ -39,11 +42,8 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 // Profile the ImageProcessing performance to convert the input image from CameraX.
 @LargeTest
@@ -52,7 +52,9 @@
     private val targetResolution: Size
 ) {
     @get:Rule
-    val useCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val labTest: LabTestRule = LabTestRule()
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/InitializationTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/InitializationTest.kt
index 3bca7d9..ef5f4da 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/InitializationTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/InitializationTest.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.content.Intent
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
 import androidx.camera.testing.CoreAppTestUtil
@@ -32,6 +33,7 @@
 import androidx.testutils.LocaleTestUtils
 import androidx.testutils.withActivity
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.runBlocking
 import org.junit.After
 import org.junit.AfterClass
@@ -39,16 +41,16 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.TimeUnit
 
 @LargeTest
 @RunWith(Parameterized::class)
 class InitializationTest(private val config: TestConfig) {
     @get:Rule
-    val useCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
     @get:Rule
     val storagePermissionRule: GrantPermissionRule =
         GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/MLKitBarcodeTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/MLKitBarcodeTest.kt
index 614ba47..9921e84 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/MLKitBarcodeTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/MLKitBarcodeTest.kt
@@ -20,6 +20,7 @@
 import android.util.Log
 import android.util.Size
 import android.view.Surface
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.ImageAnalysis
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
@@ -30,11 +31,13 @@
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
 import com.google.common.truth.Truth.assertWithMessage
-import com.google.mlkit.vision.barcode.common.Barcode.FORMAT_QR_CODE
 import com.google.mlkit.vision.barcode.BarcodeScanner
 import com.google.mlkit.vision.barcode.BarcodeScannerOptions
 import com.google.mlkit.vision.barcode.BarcodeScanning
+import com.google.mlkit.vision.barcode.common.Barcode.FORMAT_QR_CODE
 import com.google.mlkit.vision.common.InputImage
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -44,8 +47,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 /*  The integration-test is for MLKit vision barcode component with CameraX ImageAnalysis use case.
     The test is for lab device test. For the local test, mark the @LabTestRule.LabTestFrontCamera,
@@ -59,7 +60,9 @@
 ) {
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val labTest: LabTestRule = LabTestRule()
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/NewActivityLifecycleTest.java b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/NewActivityLifecycleTest.java
index ab53a5b..48ba511 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/NewActivityLifecycleTest.java
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/NewActivityLifecycleTest.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.content.Intent;
 
+import androidx.camera.camera2.Camera2Config;
 import androidx.camera.lifecycle.ProcessCameraProvider;
 import androidx.camera.testing.CameraUtil;
 import androidx.camera.testing.CoreAppTestUtil;
@@ -73,7 +74,9 @@
             new ActivityTestRule<>(CameraXActivity.class, true, false);
 
     @Rule
-    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     @Rule
     public GrantPermissionRule mStoragePermissionRule =
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/TakePictureTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/TakePictureTest.kt
index a9dc4f0..09ccab3 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/TakePictureTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/TakePictureTest.kt
@@ -18,6 +18,7 @@
 
 import android.Manifest
 import android.content.Context
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
 import androidx.camera.testing.CoreAppTestUtil
@@ -30,20 +31,21 @@
 import androidx.test.filters.LargeTest
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.GrantPermissionRule
+import java.util.concurrent.TimeUnit
 import org.junit.AfterClass
 import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
-import java.util.concurrent.TimeUnit
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
 class TakePictureTest {
     @get:Rule
-    val mUseCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val mPermissionRule: GrantPermissionRule =
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ToggleButtonUITest.java b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ToggleButtonUITest.java
index 25f75e6..7951333 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ToggleButtonUITest.java
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ToggleButtonUITest.java
@@ -32,6 +32,7 @@
 
 import android.content.Intent;
 
+import androidx.camera.camera2.Camera2Config;
 import androidx.camera.core.CameraInfo;
 import androidx.camera.core.CameraSelector;
 import androidx.camera.core.ImageCapture;
@@ -85,7 +86,9 @@
                     false);
 
     @Rule
-    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
     @Rule
     public GrantPermissionRule mStoragePermissionRule =
             GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt
index f6cf786..db385e7 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/UseCaseCombinationTest.kt
@@ -29,6 +29,7 @@
 import androidx.camera.testing.fakes.FakeLifecycleOwner
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -39,7 +40,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.TimeUnit
 
 private val DEFAULT_SELECTOR = CameraSelector.DEFAULT_BACK_CAMERA
 
@@ -52,7 +52,9 @@
 ) {
 
     @get:Rule
-    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val cameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(cameraConfig)
+    )
 
     companion object {
         @JvmStatic
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/YuvToRgbConverterTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/YuvToRgbConverterTest.kt
index df4c80d..8a145f1 100644
--- a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/YuvToRgbConverterTest.kt
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/YuvToRgbConverterTest.kt
@@ -30,6 +30,8 @@
 import androidx.camera.testing.fakes.FakeLifecycleOwner
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.LargeTest
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.runBlocking
@@ -40,11 +42,8 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 // Test the YubToRgbConverter to convert the input image from CameraX
 @LargeTest
@@ -54,7 +53,9 @@
     private val cameraXConfig: CameraXConfig
 ) {
     @get:Rule
-    val useCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(cameraXConfig)
+    )
 
     @get:Rule
     val labTest: LabTestRule = LabTestRule()
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ImageCaptureExtenderValidationTest.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ImageCaptureExtenderValidationTest.kt
index 1baf61ac..0e9daa6 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ImageCaptureExtenderValidationTest.kt
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ImageCaptureExtenderValidationTest.kt
@@ -20,6 +20,7 @@
 import android.content.Intent
 import android.hardware.camera2.CameraCharacteristics
 import android.os.Build
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.interop.Camera2CameraInfo
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.impl.ImageCaptureConfig
@@ -30,6 +31,7 @@
 import androidx.camera.integration.extensions.utils.CameraSelectorUtil
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.CoreAppTestUtil
 import androidx.camera.testing.fakes.FakeLifecycleOwner
 import androidx.camera.testing.waitForIdle
@@ -41,6 +43,7 @@
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -51,7 +54,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.TimeUnit
 
 private const val BASIC_SAMPLE_PACKAGE = "androidx.camera.integration.extensions"
 
@@ -63,7 +65,9 @@
     private val extensionMode: Int
 ) {
     @get:Rule
-    val useCamera = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
 
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ImageCaptureTest.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ImageCaptureTest.kt
index 17be3dd..a483822 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ImageCaptureTest.kt
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ImageCaptureTest.kt
@@ -19,8 +19,10 @@
 import android.Manifest
 import android.content.Context
 import android.content.Intent
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.integration.extensions.util.ExtensionsTestUtil
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.CoreAppTestUtil
 import androidx.camera.testing.waitForIdle
 import androidx.test.core.app.ActivityScenario
@@ -51,7 +53,9 @@
 class ImageCaptureTest(private val cameraId: String, private val extensionMode: Int) {
 
     @get:Rule
-    val useCamera = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val storagePermissionRule =
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewExtenderValidationTest.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewExtenderValidationTest.kt
index f5bb9db..f707563 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewExtenderValidationTest.kt
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewExtenderValidationTest.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.hardware.camera2.CameraCharacteristics
 import android.os.Build
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.interop.Camera2CameraInfo
 import androidx.camera.core.CameraSelector
 import androidx.camera.extensions.ExtensionsManager
@@ -31,11 +32,13 @@
 import androidx.camera.integration.extensions.utils.CameraSelectorUtil
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.fakes.FakeLifecycleOwner
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.SdkSuppress
 import androidx.test.filters.SmallTest
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -46,7 +49,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.TimeUnit
 
 @SmallTest
 @RunWith(Parameterized::class)
@@ -56,7 +58,9 @@
     private val extensionMode: Int
 ) {
     @get:Rule
-    val useCamera = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
 
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.kt
index 8669162..221c834 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.kt
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.kt
@@ -23,6 +23,7 @@
 import android.os.Handler
 import android.os.HandlerThread
 import android.util.Size
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.camera2.interop.Camera2CameraInfo
 import androidx.camera.core.CameraFilter
 import androidx.camera.core.CameraInfo
@@ -42,6 +43,7 @@
 import androidx.camera.integration.extensions.utils.CameraSelectorUtil
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.GLUtil
 import androidx.camera.testing.SurfaceTextureProvider
 import androidx.camera.testing.SurfaceTextureProvider.SurfaceTextureCallback
@@ -52,6 +54,8 @@
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import junit.framework.AssertionFailedError
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
@@ -65,8 +69,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 @LargeTest
 @RunWith(Parameterized::class)
@@ -76,7 +78,9 @@
     private val extensionMode: Int
 ) {
     @get:Rule
-    val useCamera = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
 
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewTest.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewTest.kt
index 1e59b05..504c0e2 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewTest.kt
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewTest.kt
@@ -19,8 +19,10 @@
 import android.Manifest
 import android.content.Context
 import android.content.Intent
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.integration.extensions.util.ExtensionsTestUtil
 import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
 import androidx.camera.testing.CoreAppTestUtil
 import androidx.camera.testing.waitForIdle
 import androidx.test.core.app.ActivityScenario
@@ -48,7 +50,9 @@
 class PreviewTest(private val cameraId: String, private val extensionMode: Int) {
 
     @get:Rule
-    val useCamera = CameraUtil.grantCameraPermissionAndPreTest()
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val storagePermissionRule =
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt
index 3ee32c0..5d45ab8 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.content.Intent
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.lifecycle.ProcessCameraProvider
 import androidx.camera.testing.CameraUtil
 import androidx.camera.testing.CoreAppTestUtil
@@ -28,11 +29,10 @@
 import androidx.test.uiautomator.UiDevice
 import androidx.testutils.withActivity
 import com.google.common.truth.Truth.assertWithMessage
+import java.util.concurrent.TimeUnit
 import org.junit.Assume
 import org.junit.BeforeClass
 import org.junit.Rule
-import org.junit.rules.TestRule
-import java.util.concurrent.TimeUnit
 
 /**
  * Base class for rotation image analysis tests.
@@ -47,7 +47,9 @@
 abstract class ImageAnalysisBaseTest<A : CameraActivity> {
 
     @get:Rule
-    val mUseCameraRule: TestRule = CameraUtil.grantCameraPermissionAndPreTest(testCameraRule)
+    val useCameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        testCameraRule, CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val mCameraActivityRules: GrantPermissionRule =
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt
index 3f6c5ca..025cb71 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt
@@ -21,6 +21,7 @@
 import android.os.Build
 import android.os.Environment
 import android.view.View
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.CameraSelector
 import androidx.camera.integration.uiwidgets.R
 import androidx.camera.lifecycle.ProcessCameraProvider
@@ -34,12 +35,11 @@
 import androidx.testutils.withActivity
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import java.util.concurrent.TimeUnit
 import org.junit.Assume.assumeFalse
 import org.junit.Assume.assumeTrue
 import org.junit.BeforeClass
 import org.junit.Rule
-import org.junit.rules.TestRule
-import java.util.concurrent.TimeUnit
 
 /**
  * Base class for rotation image capture tests.
@@ -56,7 +56,9 @@
 abstract class ImageCaptureBaseTest<A : CameraActivity> {
 
     @get:Rule
-    val mUseCameraRule: TestRule = CameraUtil.grantCameraPermissionAndPreTest(testCameraRule)
+    val useCameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        testCameraRule, CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val mCameraActivityRules: GrantPermissionRule =
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPager2ActivityTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPager2ActivityTest.kt
index 09aa803..2eac455 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPager2ActivityTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPager2ActivityTest.kt
@@ -21,6 +21,7 @@
 import android.graphics.SurfaceTexture
 import android.view.TextureView
 import android.view.View
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.CameraSelector
 import androidx.camera.integration.uiwidgets.R
 import androidx.camera.testing.CameraUtil
@@ -39,6 +40,8 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.async
 import kotlinx.coroutines.runBlocking
@@ -46,11 +49,8 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 @RunWith(Parameterized::class)
 @LargeTest
@@ -70,7 +70,9 @@
     }
 
     @get:Rule
-    val mUseCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest(testCameraRule)
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        testCameraRule, CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val mDevice =
         UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt
index f609ccc..99c9316 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/viewpager/ViewPagerActivityTest.kt
@@ -21,6 +21,7 @@
 import android.graphics.SurfaceTexture
 import android.view.TextureView
 import android.view.View
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.CameraSelector
 import androidx.camera.integration.uiwidgets.R
 import androidx.camera.testing.CameraUtil
@@ -39,6 +40,8 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.async
 import kotlinx.coroutines.runBlocking
@@ -46,11 +49,8 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 @RunWith(Parameterized::class)
 @LargeTest
@@ -70,7 +70,9 @@
     }
 
     @get:Rule
-    val mUseCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest(testCameraRule)
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        testCameraRule, CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     private val mDevice =
         UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
diff --git a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
index 1716025..28fe8db 100644
--- a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
+++ b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
@@ -24,6 +24,7 @@
 import android.net.Uri
 import android.os.Build
 import android.view.Surface
+import androidx.camera.camera2.Camera2Config
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.ImageAnalysis
 import androidx.camera.core.ImageCapture
@@ -57,6 +58,8 @@
 import com.google.common.collect.ImmutableList
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit
 import org.junit.After
 import org.junit.Assert
 import org.junit.Assume
@@ -65,10 +68,7 @@
 import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
-import org.junit.rules.TestRule
 import org.junit.runner.RunWith
-import java.util.concurrent.Semaphore
-import java.util.concurrent.TimeUnit
 
 /**
  * Instrument tests for [CameraControllerFragment].
@@ -93,7 +93,10 @@
     }
 
     @get:Rule
-    val useCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest(testCameraRule)
+    val useCameraRule = CameraUtil.grantCameraPermissionAndPreTest(
+        testCameraRule,
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
 
     @get:Rule
     val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(
diff --git a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/PreviewViewFragmentTest.java b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/PreviewViewFragmentTest.java
index 1a73700..36841e3 100644
--- a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/PreviewViewFragmentTest.java
+++ b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/PreviewViewFragmentTest.java
@@ -27,6 +27,7 @@
 import android.app.Instrumentation;
 
 import androidx.annotation.NonNull;
+import androidx.camera.camera2.Camera2Config;
 import androidx.camera.core.CameraSelector;
 import androidx.camera.testing.CameraUtil;
 import androidx.camera.testing.CoreAppTestUtil;
@@ -58,7 +59,9 @@
     private static final int PREVIEW_UPDATE_COUNT = 30;
 
     @Rule
-    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest(
+            new CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    );
 
     @Rule
     public GrantPermissionRule mStoragePermissionRule =
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ComposeUiFragment.kt b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ComposeUiFragment.kt
index 5243401..0330c7d 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ComposeUiFragment.kt
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/ComposeUiFragment.kt
@@ -17,11 +17,17 @@
 package androidx.camera.integration.view
 
 import android.os.Bundle
+import android.util.Log
 import android.view.LayoutInflater
+import android.view.MotionEvent
 import android.view.View
 import android.view.ViewGroup
 import android.widget.LinearLayout
+import androidx.camera.core.Camera
 import androidx.camera.core.CameraSelector
+import androidx.camera.core.FocusMeteringAction
+import androidx.camera.core.FocusMeteringResult
+import androidx.camera.core.MeteringPointFactory
 import androidx.camera.core.Preview
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.integration.view.MainActivity.CAMERA_DIRECTION_BACK
@@ -32,8 +38,13 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.platform.ComposeView
 import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.content.ContextCompat
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.LifecycleOwner
+import com.google.common.util.concurrent.FutureCallback
+import com.google.common.util.concurrent.Futures
+
+private const val TAG = "ComposeUiFragment"
 
 class ComposeUiFragment : Fragment() {
 
@@ -83,7 +94,8 @@
         val cameraSelector = getCameraSelector()
 
         preview.setSurfaceProvider(previewView.surfaceProvider)
-        cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)
+        val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)
+        setUpFocusAndMetering(camera, previewView)
     }
 
     private fun getCameraSelector(): CameraSelector {
@@ -99,4 +111,33 @@
         }
         return cameraSelector
     }
+
+    private fun setUpFocusAndMetering(camera: Camera, previewView: PreviewView) {
+        previewView.setOnTouchListener { _, motionEvent: MotionEvent ->
+            when (motionEvent.action) {
+                MotionEvent.ACTION_DOWN -> return@setOnTouchListener true
+                MotionEvent.ACTION_UP -> {
+                    val factory: MeteringPointFactory = previewView.meteringPointFactory
+                    val action = FocusMeteringAction.Builder(
+                        factory.createPoint(motionEvent.x, motionEvent.y)
+                    ).build()
+                    Futures.addCallback(
+                        camera.cameraControl.startFocusAndMetering(action),
+                        object : FutureCallback<FocusMeteringResult?> {
+                            override fun onSuccess(result: FocusMeteringResult?) {
+                                Log.d(TAG, "Focus and metering succeeded")
+                            }
+
+                            override fun onFailure(t: Throwable) {
+                                Log.e(TAG, "Focus and metering failed", t)
+                            }
+                        },
+                        ContextCompat.getMainExecutor(requireContext())
+                    )
+                    return@setOnTouchListener true
+                }
+                else -> return@setOnTouchListener false
+            }
+        }
+    }
 }
diff --git a/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml b/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
index 16557c9..19c1727 100644
--- a/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/showcase/automotive/src/main/AndroidManifest.xml
@@ -34,7 +34,6 @@
   <!-- For Access to Car Hardware. -->
   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
   <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
-  <uses-permission android:name="android.car.permission.CAR_MILEAGE"/>
   <uses-permission android:name="android.car.permission.CAR_SPEED"/>
   <uses-permission android:name="android.car.permission.CAR_INFO"/>
   <uses-permission android:name="android.car.permission.CAR_ENERGY"/>
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/MapTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/MapTemplateDemoScreen.java
new file mode 100644
index 0000000..b5cc466
--- /dev/null
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/MapTemplateDemoScreen.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.car.app.sample.showcase.common.navigation;
+
+import static androidx.car.app.CarToast.LENGTH_SHORT;
+import static androidx.car.app.model.Action.FLAG_PRIMARY;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
+import androidx.car.app.CarContext;
+import androidx.car.app.CarToast;
+import androidx.car.app.Screen;
+import androidx.car.app.annotations.ExperimentalCarApi;
+import androidx.car.app.model.Action;
+import androidx.car.app.model.ActionStrip;
+import androidx.car.app.model.CarColor;
+import androidx.car.app.model.CarIcon;
+import androidx.car.app.model.Header;
+import androidx.car.app.model.Pane;
+import androidx.car.app.model.Row;
+import androidx.car.app.model.Template;
+import androidx.car.app.navigation.model.MapController;
+import androidx.car.app.navigation.model.MapTemplate;
+import androidx.car.app.sample.showcase.common.R;
+import androidx.car.app.sample.showcase.common.navigation.routing.RoutingDemoModels;
+import androidx.car.app.versioning.CarAppApiLevels;
+import androidx.core.graphics.drawable.IconCompat;
+
+/** Simple demo of how to present a map template. */
+public class MapTemplateDemoScreen extends Screen {
+    @Nullable
+    private final IconCompat mPaneImage;
+
+    @Nullable
+    private final IconCompat mRowLargeIcon;
+
+    private boolean mIsFavorite = false;
+
+    protected MapTemplateDemoScreen(@NonNull CarContext carContext) {
+        super(carContext);
+        Resources resources = getCarContext().getResources();
+        Bitmap bitmap = BitmapFactory.decodeResource(resources, R.drawable.patio);
+        mPaneImage = IconCompat.createWithBitmap(bitmap);
+        mRowLargeIcon = IconCompat.createWithResource(getCarContext(),
+                R.drawable.ic_fastfood_white_48dp);
+    }
+
+    @OptIn(markerClass = ExperimentalCarApi.class)
+    @NonNull
+    @Override
+    public Template onGetTemplate() {
+        int listLimit = 4;
+
+        Pane.Builder paneBuilder = new Pane.Builder();
+        for (int i = 0; i < listLimit; i++) {
+            paneBuilder.addRow(createRow(i));
+        }
+
+        // Also set a large image outside of the rows.
+        paneBuilder.setImage(new CarIcon.Builder(mPaneImage).build());
+
+        Action.Builder primaryActionBuilder = new Action.Builder()
+                .setTitle("Reserve Chair")
+                .setBackgroundColor(CarColor.BLUE)
+                .setOnClickListener(
+                        () -> CarToast.makeText(
+                                        getCarContext(),
+                                        "Reserve/Primary button pressed",
+                                        LENGTH_SHORT)
+                                .show());
+        if (getCarContext().getCarAppApiLevel() >= CarAppApiLevels.LEVEL_4) {
+            primaryActionBuilder.setFlags(FLAG_PRIMARY);
+        }
+
+        paneBuilder
+                .addAction(primaryActionBuilder.build())
+                .addAction(
+                        new Action.Builder()
+                                .setTitle("Options")
+                                .setOnClickListener(
+                                        () -> CarToast.makeText(
+                                                        getCarContext(),
+                                                        "Options button pressed",
+                                                        LENGTH_SHORT)
+                                                .show())
+                                .build());
+
+        Header header = new Header.Builder()
+                .setStartHeaderAction(Action.APP_ICON)
+                .addEndHeaderAction(new Action.Builder()
+                        .setIcon(
+                                new CarIcon.Builder(
+                                        IconCompat.createWithResource(
+                                                getCarContext(),
+                                                mIsFavorite
+                                                        ? R.drawable.ic_favorite_filled_white_24dp
+                                                        : R.drawable.ic_favorite_white_24dp))
+                                        .build())
+                        .setOnClickListener(() -> {
+                            CarToast.makeText(
+                                            getCarContext(),
+                                            mIsFavorite ? "Not a favorite!" : "Favorite!",
+                                            LENGTH_SHORT)
+                                    .show();
+                            mIsFavorite = !mIsFavorite;
+                            invalidate();
+                        })
+                        .build())
+                .addEndHeaderAction(new Action.Builder()
+                        .setOnClickListener(() -> finish())
+                        .setIcon(
+                                new CarIcon.Builder(
+                                        IconCompat.createWithResource(
+                                                getCarContext(),
+                                                R.drawable.ic_close_white_24dp))
+                                        .build())
+                        .build())
+                .setTitle("Map Template with Pane Demo")
+                .build();
+
+
+        MapController mapController = new MapController.Builder()
+                .setMapActionStrip(RoutingDemoModels.getMapActionStrip(getCarContext()))
+                .build();
+
+        ActionStrip actionStrip = new ActionStrip.Builder()
+                .addAction(
+                        new Action.Builder()
+                                .setOnClickListener(
+                                        () -> CarToast.makeText(
+                                                        getCarContext(),
+                                                        "Bug reported!",
+                                                        CarToast.LENGTH_SHORT)
+                                                .show())
+                                .setIcon(
+                                        new CarIcon.Builder(
+                                                IconCompat.createWithResource(
+                                                        getCarContext(),
+                                                        R.drawable.ic_bug_report_24px))
+                                                .build())
+                                .setFlags(Action.FLAG_IS_PERSISTENT)
+                                .build())
+                .build();
+
+        MapTemplate.Builder builder = new MapTemplate.Builder()
+                .setActionStrip(actionStrip)
+                .setPane(paneBuilder.build())
+                .setHeader(header)
+                .setMapController(mapController);
+
+        return builder.build();
+    }
+
+    private Row createRow(int index) {
+        switch (index) {
+            case 0:
+                // Row with a large image.
+                return new Row.Builder()
+                        .setTitle("Row with a large image and long text long text long text long "
+                                + "text long text")
+                        .addText("Text text text")
+                        .addText("Text text text")
+                        .setImage(new CarIcon.Builder(mRowLargeIcon).build())
+                        .build();
+            default:
+                return new Row.Builder()
+                        .setTitle("Row title " + (index + 1))
+                        .addText("R"
+                                + "ow text 1")
+                        .addText("Row text 2")
+                        .build();
+
+        }
+    }
+}
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationDemosScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationDemosScreen.java
index d118696..c6a28de 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationDemosScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/navigation/NavigationDemosScreen.java
@@ -99,6 +99,15 @@
                                                 .push(new NavigationMapOnlyScreen(getCarContext())))
                         .build());
 
+        listBuilder.addItem(
+                new Row.Builder()
+                        .setTitle("Map Template with Pane Demo")
+                        .setOnClickListener(
+                                () ->
+                                        getScreenManager()
+                                                .push(new MapTemplateDemoScreen(getCarContext())))
+                        .build());
+
         return new ListTemplate.Builder()
                 .setSingleList(listBuilder.build())
                 .setTitle("Navigation Demos")
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java
index d3dc5b5..04fdc09 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/renderer/CarHardwareRenderer.java
@@ -16,6 +16,8 @@
 
 package androidx.car.app.sample.showcase.common.renderer;
 
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
+
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
@@ -407,18 +409,23 @@
             canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
             verticalPos += height;
 
-            // Prepare text for Odometer
-            info = new StringBuilder();
-            if (!mHasMileagePermission) {
-                info.append("No Mileage Permission.");
-            } else if (mMileage == null) {
-                info.append("Fetching mileage.");
-            } else {
-                info.append(generateCarValueText("Odometer", mMileage.getOdometerMeters(), " m. "));
-                info.append(generateCarValueText("Unit", mMileage.getDistanceDisplayUnit(), ". "));
+            // Prepare text for Odometer, skip for AAOS
+            if (!mCarContext.getPackageManager().hasSystemFeature(
+                    FEATURE_AUTOMOTIVE)) {
+                info = new StringBuilder();
+                if (!mHasMileagePermission) {
+                    info.append("No Mileage Permission.");
+                } else if (mMileage == null) {
+                    info.append("Fetching mileage.");
+                } else {
+                    info.append(
+                            generateCarValueText("Odometer", mMileage.getOdometerMeters(), " m. "));
+                    info.append(
+                            generateCarValueText("Unit", mMileage.getDistanceDisplayUnit(), ". "));
+                }
+                canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
+                verticalPos += height;
             }
-            canvas.drawText(info.toString(), LEFT_MARGIN, verticalPos, mCarInfoPaint);
-            verticalPos += height;
 
             if (mCarContext.getCarAppApiLevel() >= CarAppApiLevels.LEVEL_4) {
                 // Prepare text for EV status
diff --git a/car/app/app-samples/showcase/common/src/main/res/drawable/ic_close_white_24dp.xml b/car/app/app-samples/showcase/common/src/main/res/drawable/ic_close_white_24dp.xml
new file mode 100644
index 0000000..5832c5a
--- /dev/null
+++ b/car/app/app-samples/showcase/common/src/main/res/drawable/ic_close_white_24dp.xml
@@ -0,0 +1,26 @@
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M6.4,19 L5,17.6 10.6,12 5,6.4 6.4,5 12,10.6 17.6,5 19,6.4 13.4,12 19,17.6 17.6,19 12,13.4Z"/>
+</vector>
diff --git a/car/app/app-samples/showcase/common/src/main/res/drawable/ic_favorite_filled_white_24dp.xml b/car/app/app-samples/showcase/common/src/main/res/drawable/ic_favorite_filled_white_24dp.xml
new file mode 100644
index 0000000..d3df144
--- /dev/null
+++ b/car/app/app-samples/showcase/common/src/main/res/drawable/ic_favorite_filled_white_24dp.xml
@@ -0,0 +1,26 @@
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,21 L10.55,19.7Q6.625,16.2 4.312,13.612Q2,11.025 2,8.15Q2,5.8 3.575,4.225Q5.15,2.65 7.5,2.65Q8.825,2.65 10,3.212Q11.175,3.775 12,4.75Q12.825,3.775 14,3.212Q15.175,2.65 16.5,2.65Q18.85,2.65 20.425,4.225Q22,5.8 22,8.15Q22,11.025 19.688,13.612Q17.375,16.2 13.45,19.7ZM12,18.3Q8.425,15.05 6.213,12.7Q4,10.35 4,8.15Q4,6.65 5,5.65Q6,4.65 7.5,4.65Q8.675,4.65 9.675,5.312Q10.675,5.975 11.05,7H12.95Q13.325,5.975 14.325,5.312Q15.325,4.65 16.5,4.65Q18,4.65 19,5.65Q20,6.65 20,8.15Q20,10.35 17.788,12.7Q15.575,15.05 12,18.3ZM12,18.3Q15.575,15.05 17.788,12.7Q20,10.35 20,8.15Q20,6.65 19,5.65Q18,4.65 16.5,4.65Q15.325,4.65 14.325,5.312Q13.325,5.975 12.95,7H11.05Q10.675,5.975 9.675,5.312Q8.675,4.65 7.5,4.65Q6,4.65 5,5.65Q4,6.65 4,8.15Q4,10.35 6.213,12.7Q8.425,15.05 12,18.3Z"/>
+</vector>
diff --git a/car/app/app-samples/showcase/common/src/main/res/drawable/ic_favorite_white_24dp.xml b/car/app/app-samples/showcase/common/src/main/res/drawable/ic_favorite_white_24dp.xml
new file mode 100644
index 0000000..7709015
--- /dev/null
+++ b/car/app/app-samples/showcase/common/src/main/res/drawable/ic_favorite_white_24dp.xml
@@ -0,0 +1,26 @@
+<!--
+  Copyright 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,21 L10.55,19.7Q6.625,16.2 4.312,13.612Q2,11.025 2,8.15Q2,5.8 3.575,4.225Q5.15,2.65 7.5,2.65Q8.825,2.65 10,3.212Q11.175,3.775 12,4.75Q12.825,3.775 14,3.212Q15.175,2.65 16.5,2.65Q18.85,2.65 20.425,4.225Q22,5.8 22,8.15Q22,11.025 19.688,13.612Q17.375,16.2 13.45,19.7ZM12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475Q12,11.475 12,11.475ZM12,18.3Q15.575,15.05 17.788,12.7Q20,10.35 20,8.15Q20,6.65 19,5.65Q18,4.65 16.5,4.65Q15.325,4.65 14.325,5.312Q13.325,5.975 12.95,7H11.05Q10.675,5.975 9.675,5.312Q8.675,4.65 7.5,4.65Q6,4.65 5,5.65Q4,6.65 4,8.15Q4,10.35 6.213,12.7Q8.425,15.05 12,18.3Z"/>
+</vector>
diff --git a/car/app/app-testing/src/main/java/androidx/car/app/testing/FakeHost.java b/car/app/app-testing/src/main/java/androidx/car/app/testing/FakeHost.java
index 8378ae5..5cb4de5 100644
--- a/car/app/app-testing/src/main/java/androidx/car/app/testing/FakeHost.java
+++ b/car/app/app-testing/src/main/java/androidx/car/app/testing/FakeHost.java
@@ -24,6 +24,7 @@
 import android.location.Location;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteException;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -141,6 +142,16 @@
         public void sendLocation(Location location) {
             // No-op.
         }
+
+        @Override
+        public void showAlert(Bundleable alert) throws RemoteException {
+            // No-op.
+        }
+
+        @Override
+        public void dismissAlert(int alertId) throws RemoteException {
+            // No-op.
+        }
     }
 
     /** Testing version of the navigation host. */
diff --git a/car/app/app/api/public_plus_experimental_1.2.0-beta03.txt b/car/app/app/api/public_plus_experimental_1.2.0-beta03.txt
index 8a2a9e3..872af06 100644
--- a/car/app/app/api/public_plus_experimental_1.2.0-beta03.txt
+++ b/car/app/app/api/public_plus_experimental_1.2.0-beta03.txt
@@ -10,8 +10,10 @@
   }
 
   public class AppManager implements androidx.car.app.managers.Manager {
+    method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public void dismissAlert(int);
     method public void invalidate();
     method public void setSurfaceCallback(androidx.car.app.SurfaceCallback?);
+    method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public void showAlert(androidx.car.app.model.Alert);
     method public void showToast(CharSequence, int);
   }
 
@@ -486,6 +488,38 @@
     method public androidx.car.app.model.ActionStrip build();
   }
 
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class Alert {
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.AlertCallbackDelegate? getCallbackDelegate();
+    method public long getDurationMillis();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public int getId();
+    method public androidx.car.app.model.CarText? getSubtitle();
+    method public androidx.car.app.model.CarText getTitle();
+  }
+
+  public static final class Alert.Builder {
+    ctor public Alert.Builder(int, androidx.car.app.model.CarText, long);
+    method public androidx.car.app.model.Alert.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Alert build();
+    method public androidx.car.app.model.Alert.Builder setCallback(androidx.car.app.model.AlertCallback);
+    method public androidx.car.app.model.Alert.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Alert.Builder setSubtitle(androidx.car.app.model.CarText);
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallback {
+    method public void onCancel(int);
+    method public void onDismiss();
+    field public static final int REASON_NOT_SUPPORTED = 3; // 0x3
+    field public static final int REASON_TIMEOUT = 1; // 0x1
+    field public static final int REASON_USER_ACTION = 2; // 0x2
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallbackDelegate {
+    method public void sendCancel(int, androidx.car.app.OnDoneCallback);
+    method public void sendDismiss(androidx.car.app.OnDoneCallback);
+  }
+
   @androidx.car.app.annotations.CarProtocol public final class CarColor {
     method public static androidx.car.app.model.CarColor createCustom(@ColorInt int, @ColorInt int);
     method @ColorInt public int getColor();
diff --git a/car/app/app/api/public_plus_experimental_current.txt b/car/app/app/api/public_plus_experimental_current.txt
index 8a2a9e3..872af06 100644
--- a/car/app/app/api/public_plus_experimental_current.txt
+++ b/car/app/app/api/public_plus_experimental_current.txt
@@ -10,8 +10,10 @@
   }
 
   public class AppManager implements androidx.car.app.managers.Manager {
+    method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public void dismissAlert(int);
     method public void invalidate();
     method public void setSurfaceCallback(androidx.car.app.SurfaceCallback?);
+    method @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public void showAlert(androidx.car.app.model.Alert);
     method public void showToast(CharSequence, int);
   }
 
@@ -486,6 +488,38 @@
     method public androidx.car.app.model.ActionStrip build();
   }
 
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class Alert {
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.AlertCallbackDelegate? getCallbackDelegate();
+    method public long getDurationMillis();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public int getId();
+    method public androidx.car.app.model.CarText? getSubtitle();
+    method public androidx.car.app.model.CarText getTitle();
+  }
+
+  public static final class Alert.Builder {
+    ctor public Alert.Builder(int, androidx.car.app.model.CarText, long);
+    method public androidx.car.app.model.Alert.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Alert build();
+    method public androidx.car.app.model.Alert.Builder setCallback(androidx.car.app.model.AlertCallback);
+    method public androidx.car.app.model.Alert.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Alert.Builder setSubtitle(androidx.car.app.model.CarText);
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallback {
+    method public void onCancel(int);
+    method public void onDismiss();
+    field public static final int REASON_NOT_SUPPORTED = 3; // 0x3
+    field public static final int REASON_TIMEOUT = 1; // 0x1
+    field public static final int REASON_USER_ACTION = 2; // 0x2
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallbackDelegate {
+    method public void sendCancel(int, androidx.car.app.OnDoneCallback);
+    method public void sendDismiss(androidx.car.app.OnDoneCallback);
+  }
+
   @androidx.car.app.annotations.CarProtocol public final class CarColor {
     method public static androidx.car.app.model.CarColor createCustom(@ColorInt int, @ColorInt int);
     method @ColorInt public int getColor();
diff --git a/car/app/app/src/main/aidl/androidx/car/app/IAppHost.aidl b/car/app/app/src/main/aidl/androidx/car/app/IAppHost.aidl
index 750188d..e48fd64 100644
--- a/car/app/app/src/main/aidl/androidx/car/app/IAppHost.aidl
+++ b/car/app/app/src/main/aidl/androidx/car/app/IAppHost.aidl
@@ -16,6 +16,7 @@
 
 package androidx.car.app;
 
+import androidx.car.app.serialization.Bundleable;
 import androidx.car.app.ISurfaceCallback;
 
 /** @hide */
@@ -31,4 +32,10 @@
 
   /** Sends the last known location to the host. */
   void sendLocation(in Location location) = 4;
+
+  /** Shows an alert to the car screen. */
+  void showAlert(in Bundleable alert) = 5;
+
+  /** Dismisses the alert if active. */
+  void dismissAlert(int alertId) = 6;
 }
diff --git a/car/app/app/src/main/aidl/androidx/car/app/model/IAlertCallback.aidl b/car/app/app/src/main/aidl/androidx/car/app/model/IAlertCallback.aidl
new file mode 100644
index 0000000..af81e47
--- /dev/null
+++ b/car/app/app/src/main/aidl/androidx/car/app/model/IAlertCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.car.app.model;
+
+import androidx.car.app.IOnDoneCallback;
+
+/** @hide */
+oneway interface IAlertCallback {
+  /** Will be triggered when the alert is cancelled. */
+  void onAlertCancelled(int reason, IOnDoneCallback callback) = 1;
+  /** Will be triggered when the alert is dismissed. */
+  void onAlertDismissed(IOnDoneCallback callback) = 2;
+}
diff --git a/car/app/app/src/main/java/androidx/car/app/AppManager.java b/car/app/app/src/main/java/androidx/car/app/AppManager.java
index 9c2561e..e1937ae 100644
--- a/car/app/app/src/main/java/androidx/car/app/AppManager.java
+++ b/car/app/app/src/main/java/androidx/car/app/AppManager.java
@@ -34,7 +34,12 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
+import androidx.car.app.annotations.ExperimentalCarApi;
+import androidx.car.app.annotations.RequiresCarApi;
 import androidx.car.app.managers.Manager;
+import androidx.car.app.model.Alert;
+import androidx.car.app.serialization.Bundleable;
+import androidx.car.app.serialization.BundlerException;
 import androidx.car.app.utils.RemoteUtils;
 import androidx.core.location.LocationListenerCompat;
 import androidx.lifecycle.Lifecycle;
@@ -128,6 +133,63 @@
         );
     }
 
+    /**
+     * Shows an alert on the car screen.
+     *
+     * <p>Alerts with the same id, in the scope of the application, are considered equal. Even if
+     * their content differ.</p>
+     *
+     * <p>Posting an alert while another alert is displayed would dismiss the old alert and replace
+     * it with the new one.</p>
+     *
+     * <p>Only navigation templates support alerts. Triggering an alert while showing a
+     * non-supported template results in the cancellation of the alert. </p>
+     *
+     * @param alert                 the alert to show
+     * @throws HostException        if the remote call fails
+     * @throws NullPointerException if {@code alert} is {@code null}
+     */
+    @RequiresCarApi(5)
+    @ExperimentalCarApi
+    public void showAlert(@NonNull Alert alert) {
+        requireNonNull(alert);
+
+        Bundleable bundle;
+        try {
+            bundle = Bundleable.create(alert);
+        } catch (BundlerException e) {
+            throw new IllegalArgumentException("Serialization failure", e);
+        }
+
+        mHostDispatcher.dispatch(
+                CarContext.APP_SERVICE,
+                "showAlert", (IAppHost host) -> {
+                    host.showAlert(bundle);
+                    return null;
+                }
+        );
+    }
+
+    /**
+     * Dismisses the alert with the given {@code id}.
+     *
+     * <p>This is a no-op if there is not an active alert with the given {@code id}</p>
+     *
+     * @param alertId     the {@code id} of the {@code alert} that should be dismissed
+     * @throws HostException        if the remote call fails
+     */
+    @RequiresCarApi(5)
+    @ExperimentalCarApi
+    public void dismissAlert(int alertId) {
+        mHostDispatcher.dispatch(
+                CarContext.APP_SERVICE,
+                "dismissAlert", (IAppHost host) -> {
+                    host.dismissAlert(alertId);
+                    return null;
+                }
+        );
+    }
+
     /** Returns the {@code IAppManager.Stub} binder. */
     IAppManager.Stub getIInterface() {
         return mAppManager;
diff --git a/car/app/app/src/main/java/androidx/car/app/model/Alert.java b/car/app/app/src/main/java/androidx/car/app/model/Alert.java
new file mode 100644
index 0000000..e292ee0
--- /dev/null
+++ b/car/app/app/src/main/java/androidx/car/app/model/Alert.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.car.app.model;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.SuppressLint;
+
+import androidx.annotation.Keep;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.car.app.annotations.CarProtocol;
+import androidx.car.app.annotations.ExperimentalCarApi;
+import androidx.car.app.annotations.RequiresCarApi;
+import androidx.car.app.model.constraints.CarIconConstraints;
+import androidx.car.app.utils.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Represents an alert with an optional icon, subtitle and actions.
+ */
+@CarProtocol
+@ExperimentalCarApi
+@RequiresCarApi(5)
+public final class Alert {
+
+    /* Maximum number of actions allowed on the alert. */
+    private static final int MAX_ACTION_COUNT = 2;
+
+    @Keep
+    private final int mId;
+    @Keep
+    @Nullable
+    private final CarIcon mIcon;
+    @Keep
+    @NonNull
+    private final CarText mTitle;
+    @Keep
+    @Nullable
+    private final CarText mSubtitle;
+    @Keep
+    @NonNull
+    private final List<Action> mActions;
+    @Keep
+    private final long mDuration;
+    @Keep
+    @Nullable
+    private final AlertCallbackDelegate mCallbackDelegate;
+
+    /** Returns the id of the alert. */
+    public int getId() {
+        return mId;
+    }
+
+    /** Returns the title displayed in the alert. */
+    @NonNull
+    public CarText getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Returns the subtitle displayed in the alert or {@code null} if the alert does
+     * not have a subtitle.
+     *
+     * @see Builder#setSubtitle(CarText)
+     */
+    @Nullable
+    public CarText getSubtitle() {
+        return mSubtitle;
+    }
+
+    /**
+     * Returns the {@link CarIcon} to display in the alert or {@code null} if the alert does
+     * not have an icon.
+     *
+     * @see Builder#setIcon(CarIcon)
+     */
+    @Nullable
+    public CarIcon getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Returns the {@link List} of {@link Action}s associated with the alert.
+     *
+     * @see Builder#addAction(Action)
+     */
+    @NonNull
+    public List<Action> getActions() {
+        return mActions;
+    }
+
+    /** Returns the maximum duration in milli seconds for which the alert can be shown. */
+    public long getDurationMillis() {
+        return mDuration;
+    }
+
+    /**
+     * Returns the {@link AlertCallbackDelegate} that should be used for this alert.
+     *
+     * @see Builder#setCallback(AlertCallbackDelegate)
+     */
+    @Nullable
+    public AlertCallbackDelegate getCallbackDelegate() {
+        return mCallbackDelegate;
+    }
+
+    @Override
+    @NonNull
+    public String toString() {
+        return "[id: " + mId + ", title: " + mTitle + ", icon: " + mIcon + "]";
+    }
+
+    Alert(Builder builder) {
+        mId = builder.mId;
+        mTitle = builder.mTitle;
+        mSubtitle = builder.mSubtitle;
+        mIcon = builder.mIcon;
+        mActions = CollectionUtils.unmodifiableCopy(builder.mActions);
+        mDuration = builder.mDuration;
+        mCallbackDelegate = builder.mCallbackDelegate;
+    }
+
+    /** Constructs an empty instance, used by serialization code. */
+    private Alert() {
+        mId = 0;
+        mTitle = CarText.create("");
+        mSubtitle = null;
+        mIcon = null;
+        mActions = new ArrayList<>();
+        mDuration = 0;
+        mCallbackDelegate = null;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mId);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof Alert)) {
+            return false;
+        }
+        Alert otherAlert = (Alert) other;
+
+        // Only compare the alertIds.
+        return mId == otherAlert.mId;
+    }
+
+    /** A builder of {@link Alert}. */
+    public static final class Builder {
+        int mId;
+        @NonNull
+        CarText mTitle;
+        @Nullable
+        CarText mSubtitle;
+        @Nullable
+        CarIcon mIcon;
+        @NonNull
+        List<Action> mActions;
+        long mDuration;
+        @Nullable
+        AlertCallbackDelegate mCallbackDelegate;
+
+        /**
+         * Creates an {@link Builder} instance.
+         *
+         * <p>Text spans are supported.
+         *
+         * @param alertId The unique identifier used for the alert. Alerts with the same id are
+         *                considered equal.
+         * @param title The title of the alert.
+         * @param durationMillis The maximum duration the alert can be shown in milli seconds.
+         * @throws NullPointerException if {@code title} is {@code null}
+         * @throws IllegalArgumentException if {@code duration} is not positive
+         * @see CarText
+         */
+        public Builder(int alertId, @NonNull CarText title, long durationMillis) {
+            if (durationMillis <= 0) {
+                throw new IllegalArgumentException("Duration should be a positive number.");
+            }
+
+            mId = alertId;
+            mTitle = requireNonNull(title);
+            mDuration = durationMillis;
+            mActions = new ArrayList<>(MAX_ACTION_COUNT);
+        }
+
+        /**
+         * Sets the subtitle to display in the alert, with support for multiple length variants.
+         *
+         * <p>Text spans are supported.
+         *
+         * @throws NullPointerException if {@code subtitle} is {@code null}
+         * @see CarText
+         */
+        @NonNull
+        public Builder setSubtitle(@NonNull CarText subtitle) {
+            mSubtitle = requireNonNull(subtitle);
+            return this;
+        }
+
+        /**
+         * Sets the icon to display in the alert.
+         *
+         * <h4>Icon Sizing Guidance</h4>
+         *
+         * To minimize scaling artifacts across a wide range of car screens, apps should provide
+         * icons targeting a 88 x 88 dp bounding box. If the icon exceeds this maximum size in
+         * either one of the dimensions, it will be scaled down to be centered inside the
+         * bounding box while preserving its aspect ratio.
+         *
+         * <p>See {@link CarIcon} for more details related to providing icon and image resources
+         * that work with different car screen pixel densities.
+         *
+         * @throws NullPointerException if {@code icon} is {@code null}
+         */
+        @NonNull
+        public Builder setIcon(@NonNull CarIcon icon) {
+            CarIconConstraints.DEFAULT.validateOrThrow(requireNonNull(icon));
+            mIcon = icon;
+            return this;
+        }
+
+        /**
+         * Adds the {@code action} to the list of actions on the alert.
+         *
+         * <p>An alert can have up to 2 actions.
+         *
+         * @throws IllegalStateException if more than 2 actions are added.
+         */
+        @NonNull
+        public Builder addAction(@NonNull Action action) {
+            if (mActions.size() >= MAX_ACTION_COUNT) {
+                throw new IllegalStateException("Cannot add more than " + MAX_ACTION_COUNT
+                        + " actions.");
+            }
+            mActions.add(action);
+            return this;
+        }
+
+        /**
+         * Sets the {@link AlertCallback} to receive alert related events.
+         *
+         * @throws NullPointerException if {@code callback} is {@code null}
+         */
+        @NonNull
+        @SuppressLint({"MissingGetterMatchingBuilder", "ExecutorRegistration"})
+        public Builder setCallback(@NonNull AlertCallback callback) {
+            mCallbackDelegate = AlertCallbackDelegateImpl.create(requireNonNull(callback));
+            return this;
+        }
+
+        /** Constructs the {@link Alert} defined by this builder. */
+        @NonNull
+        public Alert build() {
+            return new Alert(this);
+        }
+    }
+}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/AlertCallback.java b/car/app/app/src/main/java/androidx/car/app/model/AlertCallback.java
new file mode 100644
index 0000000..80fc60b
--- /dev/null
+++ b/car/app/app/src/main/java/androidx/car/app/model/AlertCallback.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.car.app.model;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.RestrictTo;
+import androidx.car.app.annotations.CarProtocol;
+import androidx.car.app.annotations.ExperimentalCarApi;
+import androidx.car.app.annotations.RequiresCarApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** A listener of dismiss events. */
+@CarProtocol
+@ExperimentalCarApi
+@RequiresCarApi(5)
+public interface AlertCallback {
+
+    /**
+     * The reason for which the alert was cancelled.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    @IntDef(
+            value = {
+                    REASON_TIMEOUT,
+                    REASON_USER_ACTION,
+                    REASON_NOT_SUPPORTED,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface Reason {
+    }
+
+    /**
+     * Indicates the cancellation is due to timeout.
+     */
+    int REASON_TIMEOUT = 1;
+
+    /**
+     * Indicates the cancellation is due to user generated action, e.g. close button being pressed.
+     */
+    int REASON_USER_ACTION = 2;
+
+    /**
+     * Indicates the cancellation is due to the request not being supported, e.g. when current
+     * template cannot display the alert.
+     */
+    int REASON_NOT_SUPPORTED = 3;
+
+    /** Notifies that a cancel event happened with given {@code reason}. */
+    void onCancel(@Reason int reason);
+
+    /** Notifies that a dismiss happened. */
+    void onDismiss();
+}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/AlertCallbackDelegate.java b/car/app/app/src/main/java/androidx/car/app/model/AlertCallbackDelegate.java
new file mode 100644
index 0000000..021e365
--- /dev/null
+++ b/car/app/app/src/main/java/androidx/car/app/model/AlertCallbackDelegate.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.car.app.model;
+
+import android.annotation.SuppressLint;
+
+import androidx.annotation.NonNull;
+import androidx.car.app.OnDoneCallback;
+import androidx.car.app.annotations.CarProtocol;
+import androidx.car.app.annotations.ExperimentalCarApi;
+import androidx.car.app.annotations.RequiresCarApi;
+
+/**
+ * A host-side interface for reporting cancel events to clients.
+ */
+@CarProtocol
+@ExperimentalCarApi
+@RequiresCarApi(5)
+public interface AlertCallbackDelegate {
+
+    /**
+     * Notifies that a cancel event happened with given {@code reason}.
+     *
+     * @param callback the {@link OnDoneCallback} to trigger when the client finishes handling
+     *                 the event
+     */
+    // This mirrors the AIDL class and is not supported to support an executor as an input.
+    @SuppressLint("ExecutorRegistration")
+    void sendCancel(@AlertCallback.Reason int reason, @NonNull OnDoneCallback callback);
+
+    /**
+     * Notifies that a dismiss event happened.
+     *
+     * @param callback the {@link OnDoneCallback} to trigger when the client finishes handling
+     *                 the event
+     */
+    // This mirrors the AIDL class and is not supported to support an executor as an input.
+    @SuppressLint("ExecutorRegistration")
+    void sendDismiss(@NonNull OnDoneCallback callback);
+}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/AlertCallbackDelegateImpl.java b/car/app/app/src/main/java/androidx/car/app/model/AlertCallbackDelegateImpl.java
new file mode 100644
index 0000000..b800e5d
--- /dev/null
+++ b/car/app/app/src/main/java/androidx/car/app/model/AlertCallbackDelegateImpl.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.car.app.model;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.SuppressLint;
+import android.os.RemoteException;
+
+import androidx.annotation.Keep;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
+import androidx.annotation.RestrictTo;
+import androidx.car.app.IOnDoneCallback;
+import androidx.car.app.OnDoneCallback;
+import androidx.car.app.annotations.ExperimentalCarApi;
+import androidx.car.app.utils.RemoteUtils;
+
+/**
+ * Implementation class for {@link AlertCallbackDelegate} to allow IPC for cancel events.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+@OptIn(markerClass = ExperimentalCarApi.class)
+public class AlertCallbackDelegateImpl implements AlertCallbackDelegate {
+
+    @Keep
+    @Nullable
+    private final IAlertCallback mCallback;
+
+    @NonNull
+    @SuppressLint("ExecutorRegistration")
+    static AlertCallbackDelegate create(@NonNull AlertCallback callback) {
+        return new AlertCallbackDelegateImpl(callback);
+    }
+
+    private AlertCallbackDelegateImpl(@NonNull AlertCallback callback) {
+        mCallback = new AlertCallbackStub(callback);
+    }
+
+    /** For serialization. */
+    private AlertCallbackDelegateImpl() {
+        mCallback = null;
+    }
+
+    @Override
+    public void sendCancel(@AlertCallback.Reason int reason, @NonNull OnDoneCallback callback) {
+        try {
+            requireNonNull(mCallback).onAlertCancelled(reason,
+                    RemoteUtils.createOnDoneCallbackStub(callback));
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void sendDismiss(@NonNull OnDoneCallback callback) {
+        try {
+            requireNonNull(mCallback)
+                    .onAlertDismissed(RemoteUtils.createOnDoneCallbackStub(callback));
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Keep // We need to keep these stub for Bundler serialization logic.
+    private static class AlertCallbackStub extends IAlertCallback.Stub {
+        private final AlertCallback mCallback;
+
+        AlertCallbackStub(AlertCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void onAlertCancelled(@AlertCallback.Reason int reason, IOnDoneCallback callback) {
+            RemoteUtils.dispatchCallFromHost(callback, "onCancel", () -> {
+                mCallback.onCancel(reason);
+                return null;
+            });
+        }
+
+        @Override
+        public void onAlertDismissed(IOnDoneCallback callback) {
+            RemoteUtils.dispatchCallFromHost(callback, "onDismiss", () -> {
+                mCallback.onDismiss();
+                return null;
+            });
+        }
+    }
+}
diff --git a/car/app/app/src/test/java/androidx/car/app/AppManagerTest.java b/car/app/app/src/test/java/androidx/car/app/AppManagerTest.java
index 14dfd94..26d4d29 100644
--- a/car/app/app/src/test/java/androidx/car/app/AppManagerTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/AppManagerTest.java
@@ -16,6 +16,8 @@
 
 package androidx.car.app;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyFloat;
@@ -36,6 +38,8 @@
 import androidx.activity.OnBackPressedCallback;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.car.app.model.Alert;
+import androidx.car.app.model.CarText;
 import androidx.car.app.model.Template;
 import androidx.car.app.serialization.Bundleable;
 import androidx.car.app.serialization.BundlerException;
@@ -74,6 +78,12 @@
     @Captor
     private ArgumentCaptor<ISurfaceCallback> mSurfaceCallbackCaptor;
 
+    @Captor
+    private ArgumentCaptor<Bundleable> mAlertCaptor;
+
+    @Captor
+    private ArgumentCaptor<Integer> mAlertIdCaptor;
+
     private Application mApplication;
     private TestCarContext mTestCarContext;
     private final HostDispatcher mHostDispatcher = new HostDispatcher();
@@ -110,6 +120,16 @@
                     public void sendLocation(Location location) throws RemoteException {
                         mMockAppHost.sendLocation(location);
                     }
+
+                    @Override
+                    public void showAlert(Bundleable alert) throws RemoteException {
+                        mMockAppHost.showAlert(alert);
+                    }
+
+                    @Override
+                    public void dismissAlert(int alertId) throws RemoteException {
+                        mMockAppHost.dismissAlert(alertId);
+                    }
                 };
         when(mMockCarHost.getHost(any())).thenReturn(appHost.asBinder());
 
@@ -513,6 +533,25 @@
         verify(mMockOnDoneCallback).onFailure(any());
     }
 
+    @Test
+    public void onShowAlert_dispatches() throws RemoteException, BundlerException {
+        mTestCarContext.getLifecycleOwner().mRegistry.setCurrentState(Lifecycle.State.CREATED);
+        Alert alert = new Alert.Builder(1, CarText.create("title"), 10).build();
+        mAppManager.showAlert(alert);
+        verify(mMockAppHost).showAlert(mAlertCaptor.capture());
+
+        assertThat(mAlertCaptor.getValue().get()).isEqualTo(alert);
+    }
+
+    @Test
+    public void onDismissAlert_dispatches() throws RemoteException, BundlerException {
+        mTestCarContext.getLifecycleOwner().mRegistry.setCurrentState(Lifecycle.State.CREATED);
+        mAppManager.dismissAlert(123);
+        verify(mMockAppHost).dismissAlert(mAlertIdCaptor.capture());
+
+        assertThat(mAlertIdCaptor.getValue()).isEqualTo(123);
+    }
+
     private static class NonBundleableTemplate implements Template {
         NonBundleableTemplate(String s) {
         }
diff --git a/car/app/app/src/test/java/androidx/car/app/CarContextTest.java b/car/app/app/src/test/java/androidx/car/app/CarContextTest.java
index 1883180..c7aec4c 100644
--- a/car/app/app/src/test/java/androidx/car/app/CarContextTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/CarContextTest.java
@@ -47,6 +47,7 @@
 import androidx.car.app.managers.Manager;
 import androidx.car.app.managers.ResultManager;
 import androidx.car.app.navigation.NavigationManager;
+import androidx.car.app.serialization.Bundleable;
 import androidx.car.app.testing.TestLifecycleOwner;
 import androidx.lifecycle.Lifecycle.Event;
 import androidx.lifecycle.Lifecycle.State;
@@ -115,6 +116,14 @@
                             @Override
                             public void sendLocation(Location location) {
                             }
+
+                            @Override
+                            public void showAlert(Bundleable alert) {
+                            }
+
+                            @Override
+                            public void dismissAlert(int alertId) {
+                            }
                         }.asBinder());
 
         TestStartCarAppStub startCarAppStub = new TestStartCarAppStub(mMockStartCarApp);
diff --git a/car/app/app/src/test/java/androidx/car/app/HostDispatcherTest.java b/car/app/app/src/test/java/androidx/car/app/HostDispatcherTest.java
index 0fcae1d..7584669 100644
--- a/car/app/app/src/test/java/androidx/car/app/HostDispatcherTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/HostDispatcherTest.java
@@ -82,6 +82,16 @@
                     public void sendLocation(Location location) throws RemoteException {
                         mMockAppHost.sendLocation(location);
                     }
+
+                    @Override
+                    public void showAlert(Bundleable alert) throws RemoteException {
+                        mMockAppHost.showAlert(alert);
+                    }
+
+                    @Override
+                    public void dismissAlert(int alertId) throws RemoteException {
+                        mMockAppHost.dismissAlert(alertId);
+                    }
                 };
 
         mNavigationHost = new INavigationHost.Stub() {
diff --git a/car/app/app/src/test/java/androidx/car/app/model/AlertCallbackDelegateTest.java b/car/app/app/src/test/java/androidx/car/app/model/AlertCallbackDelegateTest.java
new file mode 100644
index 0000000..a123c41
--- /dev/null
+++ b/car/app/app/src/test/java/androidx/car/app/model/AlertCallbackDelegateTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.car.app.model;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import androidx.car.app.OnDoneCallback;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+/** Tests for {@link AlertCallbackDelegateImpl}. */
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class AlertCallbackDelegateTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    AlertCallback mMockAlertCallback;
+
+    @Test
+    public void sendCancel_reason_timeout() {
+        AlertCallbackDelegate delegate = AlertCallbackDelegateImpl.create(mMockAlertCallback);
+
+        OnDoneCallback onDoneCallback = mock(OnDoneCallback.class);
+        delegate.sendCancel(AlertCallback.REASON_TIMEOUT, onDoneCallback);
+        verify(mMockAlertCallback).onCancel(AlertCallback.REASON_TIMEOUT);
+        verify(onDoneCallback).onSuccess(null);
+        verify(onDoneCallback, never()).onFailure(any());
+    }
+
+    @Test
+    public void sendCancel_reason_userAction() {
+        AlertCallbackDelegate delegate = AlertCallbackDelegateImpl.create(mMockAlertCallback);
+
+        OnDoneCallback onDoneCallback = mock(OnDoneCallback.class);
+        delegate.sendCancel(AlertCallback.REASON_USER_ACTION, onDoneCallback);
+        verify(mMockAlertCallback).onCancel(AlertCallback.REASON_USER_ACTION);
+        verify(onDoneCallback).onSuccess(null);
+        verify(onDoneCallback, never()).onFailure(any());
+    }
+
+    @Test
+    public void sendDismiss() {
+        AlertCallbackDelegate delegate = AlertCallbackDelegateImpl.create(mMockAlertCallback);
+
+        OnDoneCallback onDoneCallback = mock(OnDoneCallback.class);
+        delegate.sendDismiss(onDoneCallback);
+        verify(mMockAlertCallback).onDismiss();
+        verify(onDoneCallback).onSuccess(null);
+        verify(onDoneCallback, never()).onFailure(any());
+    }
+}
diff --git a/car/app/app/src/test/java/androidx/car/app/model/AlertTest.java b/car/app/app/src/test/java/androidx/car/app/model/AlertTest.java
new file mode 100644
index 0000000..a7c53dd
--- /dev/null
+++ b/car/app/app/src/test/java/androidx/car/app/model/AlertTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.car.app.model;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+
+import androidx.car.app.OnDoneCallback;
+import androidx.car.app.TestUtils;
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+/** Tests for {@link Action}. */
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class AlertTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    @Test
+    public void create_throws_invalidDuration() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> new Alert.Builder(1, CarText.create("title"), 0));
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> new Alert.Builder(1, CarText.create("title"), -1));
+    }
+
+    @Test
+    public void create_throws_invalid_carIcon() {
+        Uri.Builder builder = new Uri.Builder();
+        builder.scheme(ContentResolver.SCHEME_CONTENT);
+        builder.appendPath("foo/bar");
+        Uri iconUri = builder.build();
+        CarIcon carIcon = new CarIcon.Builder(IconCompat.createWithContentUri(iconUri)).build();
+        CarText title = CarText.create("title");
+        assertThrows(IllegalArgumentException.class,
+                () -> new Alert.Builder(1, title, 10).setIcon(carIcon));
+    }
+
+    @Test
+    public void create_default() {
+        CarText title = CarText.create("title");
+        Alert alert = new Alert.Builder(123, title, 1234).build();
+        assertThat(alert.getId()).isEqualTo(123);
+        assertThat(alert.getTitle()).isEqualTo(title);
+        assertThat(alert.getDurationMillis()).isEqualTo(1234);
+        assertThat(alert.getIcon()).isNull();
+        assertThat(alert.getSubtitle()).isNull();
+        assertThat(alert.getActions()).isEmpty();
+        assertThat(alert.getCallbackDelegate()).isNull();
+    }
+
+    @Test
+    public void create_setIcon() {
+        CarIcon icon = TestUtils.getTestCarIcon(ApplicationProvider.getApplicationContext(),
+                "ic_test_1");
+        CarText title = CarText.create("title");
+        Alert alert = new Alert.Builder(123, title, 1234).setIcon(icon).build();
+        assertThat(alert.getIcon()).isEqualTo(icon);
+    }
+
+    @Test
+    public void create_titleHasTextVariants() {
+        CarText title = new CarText.Builder("foo long text").addVariant("foo").build();
+        Alert alert = new Alert.Builder(123, title, 1234).build();
+        assertThat(alert.getTitle()).isNotNull();
+        assertThat(alert.getTitle().toCharSequence().toString()).isEqualTo("foo long text");
+        assertThat(alert.getTitle().getVariants().get(0).toString()).isEqualTo("foo");
+    }
+
+    @Test
+    public void create_withActions() {
+        CarText title = CarText.create("title");
+        Action action1 = Action.PAN;
+        Action action2 = Action.BACK;
+        Alert alert = new Alert.Builder(123, title, 1234).addAction(action1)
+                .addAction(action2).build();
+        assertThat(alert.getActions()).isNotNull();
+        assertThat(alert.getActions().size()).isEqualTo(2);
+        assertThat(alert.getActions().get(0)).isEqualTo(action1);
+        assertThat(alert.getActions().get(1)).isEqualTo(action2);
+    }
+
+    @Test
+    public void create_throws_tooManyActions() {
+        CarText title = CarText.create("title");
+        Action action1 = Action.PAN;
+        Action action2 = Action.BACK;
+        Action action3 = Action.APP_ICON;
+        assertThrows(
+                IllegalStateException.class,
+                () -> new Alert.Builder(1, title, 1234).addAction(action1)
+                        .addAction(action2).addAction(action3));
+    }
+
+    @Test
+    public void onDismiss() {
+        AlertCallback alertCallback = mock(AlertCallback.class);
+        CarText title = CarText.create("foo");
+        Alert alert = new Alert.Builder(123, title, 1234)
+                .setCallback(alertCallback)
+                .build();
+        OnDoneCallback onDoneCallback = mock(OnDoneCallback.class);
+        assertThat(alert.getCallbackDelegate()).isNotNull();
+        alert.getCallbackDelegate().sendDismiss(onDoneCallback);
+        verify(alertCallback).onDismiss();
+        verify(onDoneCallback).onSuccess(null);
+    }
+
+    @Test
+    public void equals() {
+        CarText title = CarText.create("foo");
+        CarText subtitle = CarText.create("sub foo");
+        CarIcon icon = CarIcon.ALERT;
+
+        Alert alert1 =
+                new Alert.Builder(1, title, 12).setSubtitle(subtitle)
+                        .setIcon(icon).build();
+        Alert alert2 =
+                new Alert.Builder(1, title, 12).setSubtitle(subtitle)
+                        .setIcon(icon).build();
+
+        assertThat(alert1).isEqualTo(alert2);
+    }
+
+    @Test
+    public void notEquals_nonMatchingId() {
+        CarText title = CarText.create("foo");
+        CarText subtitle = CarText.create("sub foo");
+        CarIcon icon = CarIcon.ALERT;
+
+        Alert alert1 =
+                new Alert.Builder(1, title, 12).setSubtitle(subtitle)
+                        .setIcon(icon).build();
+        Alert alert2 =
+                new Alert.Builder(2, title, 12).setSubtitle(subtitle)
+                        .setIcon(icon).build();
+
+        assertThat(alert1).isNotEqualTo(alert2);
+    }
+
+    @Test
+    public void equals_nonMatchingTitle() {
+        CarText title1 = CarText.create("foo");
+        CarText title2 = CarText.create("bar");
+        CarText subtitle = CarText.create("sub foo");
+        CarIcon icon = CarIcon.ALERT;
+
+        Alert alert1 =
+                new Alert.Builder(1, title1, 12).setSubtitle(subtitle)
+                        .setIcon(icon).build();
+        Alert alert2 =
+                new Alert.Builder(1, title2, 12).setSubtitle(subtitle)
+                        .setIcon(icon).build();
+
+        assertThat(alert1).isEqualTo(alert2);
+    }
+
+    @Test
+    public void equals_nonMatchingIcon() {
+        CarText title = CarText.create("foo");
+        CarText subtitle = CarText.create("sub foo");
+        CarIcon icon1 = CarIcon.ALERT;
+        CarIcon icon2 = CarIcon.BACK;
+
+        Alert alert1 =
+                new Alert.Builder(1, title, 12).setSubtitle(subtitle)
+                        .setIcon(icon1).build();
+        Alert alert2 =
+                new Alert.Builder(1, title, 12).setSubtitle(subtitle)
+                        .setIcon(icon2).build();
+
+        assertThat(alert1).isEqualTo(alert2);
+    }
+
+    @Test
+    public void equals_nonMatchingDuration() {
+        CarText title = CarText.create("foo");
+        CarText subtitle = CarText.create("sub foo");
+        CarIcon icon = CarIcon.ALERT;
+
+        Alert alert1 =
+                new Alert.Builder(1, title, 12).setSubtitle(subtitle)
+                        .setIcon(icon).build();
+        Alert alert2 =
+                new Alert.Builder(1, title, 13).setSubtitle(subtitle)
+                        .setIcon(icon).build();
+
+        assertThat(alert1).isEqualTo(alert2);
+    }
+
+
+}
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/SanityCheckCodegenTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/SanityCheckCodegenTests.kt
index 237d15f..38c974d 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/SanityCheckCodegenTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/SanityCheckCodegenTests.kt
@@ -57,4 +57,21 @@
         """
         )
     }
+
+    // Regression test for b/222979253
+    fun testLabeledLambda() = ensureSetup {
+        testCompile(
+            """
+                import androidx.compose.runtime.Composable
+
+                @Composable
+                fun test(): Unit {
+                    Box box@{}
+                }
+
+                @Composable
+                fun Box(content: @Composable () -> Unit) {}
+        """
+        )
+    }
 }
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableTargetChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableTargetChecker.kt
index 34b23fb..3973744 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableTargetChecker.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableTargetChecker.kt
@@ -50,6 +50,7 @@
 import org.jetbrains.kotlin.psi.KtFile
 import org.jetbrains.kotlin.psi.KtFunction
 import org.jetbrains.kotlin.psi.KtFunctionLiteral
+import org.jetbrains.kotlin.psi.KtLabeledExpression
 import org.jetbrains.kotlin.psi.KtLambdaArgument
 import org.jetbrains.kotlin.psi.KtLambdaExpression
 import org.jetbrains.kotlin.psi.KtProperty
@@ -349,9 +350,18 @@
         return PsiElementNode(element, bindingContext)
     }
 
-    private fun lambdaOrNull(element: PsiElement): KtFunctionLiteral? =
-        (element as? KtLambdaArgument)?.children?.firstOrNull()?.children
-            ?.firstOrNull() as KtFunctionLiteral?
+    private fun lambdaOrNull(element: PsiElement): KtFunctionLiteral? {
+        var container = (element as? KtLambdaArgument)?.children?.singleOrNull()
+        while (true) {
+            container = when (container) {
+                null -> return null
+                is KtLabeledExpression -> container.lastChild
+                is KtFunctionLiteral -> return container
+                is KtLambdaExpression -> container.children.single()
+                else -> throw Error("Unknown type: ${container.javaClass}")
+            }
+        }
+    }
 
     private fun descriptorToInferenceNode(
         descriptor: CallableDescriptor,
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
index 6c4ebb8..8947c55 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
@@ -74,6 +74,7 @@
             6300 to "1.2.0-alpha04",
             6400 to "1.2.0-alpha05",
             6500 to "1.2.0-alpha06",
+            6600 to "1.2.0-alpha07",
         )
 
         /**
@@ -86,7 +87,7 @@
          * The maven version string of this compiler. This string should be updated before/after every
          * release.
          */
-        const val compilerVersion: String = "1.2.0-alpha06"
+        const val compilerVersion: String = "1.2.0-alpha07"
         private val minimumRuntimeVersion: String
             get() = versionTable[minimumRuntimeVersionInt] ?: "unknown"
     }
diff --git a/compose/foundation/foundation-layout/api/current.txt b/compose/foundation/foundation-layout/api/current.txt
index f370e39..36b9fc9 100644
--- a/compose/foundation/foundation-layout/api/current.txt
+++ b/compose/foundation/foundation-layout/api/current.txt
@@ -221,7 +221,7 @@
     method public static androidx.compose.foundation.layout.WindowInsets WindowInsets(optional int left, optional int top, optional int right, optional int bottom);
     method public static androidx.compose.foundation.layout.WindowInsets WindowInsets(optional float left, optional float top, optional float right, optional float bottom);
     method public static androidx.compose.foundation.layout.WindowInsets add(androidx.compose.foundation.layout.WindowInsets, androidx.compose.foundation.layout.WindowInsets insets);
-    method @androidx.compose.runtime.Composable public static androidx.compose.foundation.layout.PaddingValues asPaddingValues(androidx.compose.foundation.layout.WindowInsets);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static androidx.compose.foundation.layout.PaddingValues asPaddingValues(androidx.compose.foundation.layout.WindowInsets);
     method public static androidx.compose.foundation.layout.PaddingValues asPaddingValues(androidx.compose.foundation.layout.WindowInsets, androidx.compose.ui.unit.Density density);
     method public static androidx.compose.foundation.layout.WindowInsets exclude(androidx.compose.foundation.layout.WindowInsets, androidx.compose.foundation.layout.WindowInsets insets);
     method public static androidx.compose.foundation.layout.WindowInsets only(androidx.compose.foundation.layout.WindowInsets, int sides);
diff --git a/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt b/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
index fa8d420..48656fc 100644
--- a/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
@@ -224,7 +224,7 @@
     method public static androidx.compose.foundation.layout.WindowInsets WindowInsets(optional int left, optional int top, optional int right, optional int bottom);
     method public static androidx.compose.foundation.layout.WindowInsets WindowInsets(optional float left, optional float top, optional float right, optional float bottom);
     method public static androidx.compose.foundation.layout.WindowInsets add(androidx.compose.foundation.layout.WindowInsets, androidx.compose.foundation.layout.WindowInsets insets);
-    method @androidx.compose.runtime.Composable public static androidx.compose.foundation.layout.PaddingValues asPaddingValues(androidx.compose.foundation.layout.WindowInsets);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static androidx.compose.foundation.layout.PaddingValues asPaddingValues(androidx.compose.foundation.layout.WindowInsets);
     method public static androidx.compose.foundation.layout.PaddingValues asPaddingValues(androidx.compose.foundation.layout.WindowInsets, androidx.compose.ui.unit.Density density);
     method public static androidx.compose.foundation.layout.WindowInsets exclude(androidx.compose.foundation.layout.WindowInsets, androidx.compose.foundation.layout.WindowInsets insets);
     method public static androidx.compose.foundation.layout.WindowInsets only(androidx.compose.foundation.layout.WindowInsets, int sides);
diff --git a/compose/foundation/foundation-layout/api/restricted_current.txt b/compose/foundation/foundation-layout/api/restricted_current.txt
index 6a61a51..e6db567 100644
--- a/compose/foundation/foundation-layout/api/restricted_current.txt
+++ b/compose/foundation/foundation-layout/api/restricted_current.txt
@@ -226,7 +226,7 @@
     method public static androidx.compose.foundation.layout.WindowInsets WindowInsets(optional int left, optional int top, optional int right, optional int bottom);
     method public static androidx.compose.foundation.layout.WindowInsets WindowInsets(optional float left, optional float top, optional float right, optional float bottom);
     method public static androidx.compose.foundation.layout.WindowInsets add(androidx.compose.foundation.layout.WindowInsets, androidx.compose.foundation.layout.WindowInsets insets);
-    method @androidx.compose.runtime.Composable public static androidx.compose.foundation.layout.PaddingValues asPaddingValues(androidx.compose.foundation.layout.WindowInsets);
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public static androidx.compose.foundation.layout.PaddingValues asPaddingValues(androidx.compose.foundation.layout.WindowInsets);
     method public static androidx.compose.foundation.layout.PaddingValues asPaddingValues(androidx.compose.foundation.layout.WindowInsets, androidx.compose.ui.unit.Density density);
     method public static androidx.compose.foundation.layout.WindowInsets exclude(androidx.compose.foundation.layout.WindowInsets, androidx.compose.foundation.layout.WindowInsets insets);
     method public static androidx.compose.foundation.layout.WindowInsets only(androidx.compose.foundation.layout.WindowInsets, int sides);
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsets.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsets.kt
index 64573de..2e37e34 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsets.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/WindowInsets.kt
@@ -18,6 +18,7 @@
 
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.ReadOnlyComposable
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -212,6 +213,7 @@
  *
  * @sample androidx.compose.foundation.layout.samples.paddingValuesSample
  */
+@ReadOnlyComposable
 @Composable
 fun WindowInsets.asPaddingValues(): PaddingValues = InsetsPaddingValues(this, LocalDensity.current)
 
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index b23774c..22673bea 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -509,7 +509,7 @@
     method public static inline <T> void itemsIndexed(androidx.compose.foundation.lazy.grid.LazyGridScope, T![] items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, optional kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.grid.LazyGridItemSpanScope,? super java.lang.Integer,? super T,androidx.compose.foundation.lazy.grid.GridItemSpan>? span, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?> contentType, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.grid.LazyGridItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
   }
 
-  public interface LazyGridItemInfo {
+  public sealed interface LazyGridItemInfo {
     method public int getColumn();
     method public int getIndex();
     method public Object getKey();
@@ -535,10 +535,10 @@
   public final class LazyGridItemPlacementAnimatorKt {
   }
 
-  @androidx.compose.runtime.Stable public interface LazyGridItemScope {
+  @androidx.compose.runtime.Stable public sealed interface LazyGridItemScope {
   }
 
-  public interface LazyGridItemSpanScope {
+  public sealed interface LazyGridItemSpanScope {
     method public int getMaxCurrentLineSpan();
     method public int getMaxLineSpan();
     property public abstract int maxCurrentLineSpan;
@@ -551,7 +551,7 @@
   public final class LazyGridKt {
   }
 
-  public interface LazyGridLayoutInfo {
+  public sealed interface LazyGridLayoutInfo {
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -571,7 +571,7 @@
   public final class LazyGridMeasureKt {
   }
 
-  public interface LazyGridScope {
+  public sealed interface LazyGridScope {
     method public void item(optional Object? key, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.lazy.grid.LazyGridItemSpanScope,androidx.compose.foundation.lazy.grid.GridItemSpan>? span, optional Object? contentType, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.lazy.grid.LazyGridItemScope,kotlin.Unit> content);
     method public void items(int count, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, optional kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.grid.LazyGridItemSpanScope,? super java.lang.Integer,androidx.compose.foundation.lazy.grid.GridItemSpan>? span, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?> contentType, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.grid.LazyGridItemScope,? super java.lang.Integer,kotlin.Unit> itemContent);
   }
diff --git a/compose/foundation/foundation/api/public_plus_experimental_current.txt b/compose/foundation/foundation/api/public_plus_experimental_current.txt
index 0ba1911..025917e 100644
--- a/compose/foundation/foundation/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation/api/public_plus_experimental_current.txt
@@ -572,7 +572,7 @@
     method public static inline <T> void itemsIndexed(androidx.compose.foundation.lazy.grid.LazyGridScope, T![] items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, optional kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.grid.LazyGridItemSpanScope,? super java.lang.Integer,? super T,androidx.compose.foundation.lazy.grid.GridItemSpan>? span, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?> contentType, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.grid.LazyGridItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
   }
 
-  public interface LazyGridItemInfo {
+  public sealed interface LazyGridItemInfo {
     method public int getColumn();
     method public int getIndex();
     method public Object getKey();
@@ -598,11 +598,11 @@
   public final class LazyGridItemPlacementAnimatorKt {
   }
 
-  @androidx.compose.runtime.Stable public interface LazyGridItemScope {
+  @androidx.compose.runtime.Stable public sealed interface LazyGridItemScope {
     method @androidx.compose.foundation.ExperimentalFoundationApi public androidx.compose.ui.Modifier animateItemPlacement(androidx.compose.ui.Modifier, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec);
   }
 
-  public interface LazyGridItemSpanScope {
+  public sealed interface LazyGridItemSpanScope {
     method public int getMaxCurrentLineSpan();
     method public int getMaxLineSpan();
     property public abstract int maxCurrentLineSpan;
@@ -615,7 +615,7 @@
   public final class LazyGridKt {
   }
 
-  public interface LazyGridLayoutInfo {
+  public sealed interface LazyGridLayoutInfo {
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -635,7 +635,7 @@
   public final class LazyGridMeasureKt {
   }
 
-  public interface LazyGridScope {
+  public sealed interface LazyGridScope {
     method public void item(optional Object? key, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.lazy.grid.LazyGridItemSpanScope,androidx.compose.foundation.lazy.grid.GridItemSpan>? span, optional Object? contentType, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.lazy.grid.LazyGridItemScope,kotlin.Unit> content);
     method public void items(int count, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, optional kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.grid.LazyGridItemSpanScope,? super java.lang.Integer,androidx.compose.foundation.lazy.grid.GridItemSpan>? span, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?> contentType, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.grid.LazyGridItemScope,? super java.lang.Integer,kotlin.Unit> itemContent);
   }
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index b23774c..22673bea 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -509,7 +509,7 @@
     method public static inline <T> void itemsIndexed(androidx.compose.foundation.lazy.grid.LazyGridScope, T![] items, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?>? key, optional kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.grid.LazyGridItemSpanScope,? super java.lang.Integer,? super T,androidx.compose.foundation.lazy.grid.GridItemSpan>? span, optional kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,?> contentType, kotlin.jvm.functions.Function3<? super androidx.compose.foundation.lazy.grid.LazyGridItemScope,? super java.lang.Integer,? super T,kotlin.Unit> itemContent);
   }
 
-  public interface LazyGridItemInfo {
+  public sealed interface LazyGridItemInfo {
     method public int getColumn();
     method public int getIndex();
     method public Object getKey();
@@ -535,10 +535,10 @@
   public final class LazyGridItemPlacementAnimatorKt {
   }
 
-  @androidx.compose.runtime.Stable public interface LazyGridItemScope {
+  @androidx.compose.runtime.Stable public sealed interface LazyGridItemScope {
   }
 
-  public interface LazyGridItemSpanScope {
+  public sealed interface LazyGridItemSpanScope {
     method public int getMaxCurrentLineSpan();
     method public int getMaxLineSpan();
     property public abstract int maxCurrentLineSpan;
@@ -551,7 +551,7 @@
   public final class LazyGridKt {
   }
 
-  public interface LazyGridLayoutInfo {
+  public sealed interface LazyGridLayoutInfo {
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -571,7 +571,7 @@
   public final class LazyGridMeasureKt {
   }
 
-  public interface LazyGridScope {
+  public sealed interface LazyGridScope {
     method public void item(optional Object? key, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.lazy.grid.LazyGridItemSpanScope,androidx.compose.foundation.lazy.grid.GridItemSpan>? span, optional Object? contentType, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.lazy.grid.LazyGridItemScope,kotlin.Unit> content);
     method public void items(int count, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, optional kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.grid.LazyGridItemSpanScope,? super java.lang.Integer,androidx.compose.foundation.lazy.grid.GridItemSpan>? span, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?> contentType, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.grid.LazyGridItemScope,? super java.lang.Integer,kotlin.Unit> itemContent);
   }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/DragGestureDetector.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/DragGestureDetector.kt
index e0614a5..06f69c0 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/DragGestureDetector.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/DragGestureDetector.kt
@@ -104,7 +104,7 @@
 
     while (true) {
         val event = awaitPointerEvent()
-        val dragEvent = event.changes.fastFirstOrNull { it.id == pointer }!!
+        val dragEvent = event.changes.fastFirstOrNull { it.id == pointer } ?: return null
         if (dragEvent.positionChangeConsumed()) {
             return null
         } else if (dragEvent.changedToUpIgnoreConsumed()) {
@@ -198,7 +198,7 @@
         return null // The pointer has already been lifted, so the gesture is canceled
     }
     val change = awaitDragOrUp(pointerId) { it.positionChangedIgnoreConsumed() }
-    return if (change.positionChangeConsumed()) null else change
+    return if (change?.positionChangeConsumed() == false) change else null
 }
 
 /**
@@ -404,7 +404,7 @@
         return null // The pointer has already been lifted, so the gesture is canceled
     }
     val change = awaitDragOrUp(pointerId) { it.positionChangeIgnoreConsumed().y != 0f }
-    return if (change.positionChangeConsumed()) null else change
+    return if (change?.positionChangeConsumed() == false) change else null
 }
 
 /**
@@ -548,7 +548,7 @@
         return null // The pointer has already been lifted, so the gesture is canceled
     }
     val change = awaitDragOrUp(pointerId) { it.positionChangeIgnoreConsumed().x != 0f }
-    return if (change.positionChangeConsumed()) null else change
+    return if (change?.positionChangeConsumed() == false) change else null
 }
 
 /**
@@ -626,7 +626,7 @@
     }
     var pointer = pointerId
     while (true) {
-        val change = awaitDragOrUp(pointer) { motionFromChange(it) != 0f }
+        val change = awaitDragOrUp(pointer) { motionFromChange(it) != 0f } ?: return false
 
         if (motionConsumed(change)) {
             return false
@@ -647,15 +647,18 @@
  * governing the drag. When the final pointer is lifted, that [PointerInputChange] is
  * returned. When a drag is detected, that [PointerInputChange] is returned. A drag is
  * only detected when [hasDragged] returns `true`.
+ *
+ * `null` is returned if there was an error in the pointer input stream and the pointer
+ * that was down was dropped before the 'up' was received.
  */
 private suspend inline fun AwaitPointerEventScope.awaitDragOrUp(
     pointerId: PointerId,
     hasDragged: (PointerInputChange) -> Boolean
-): PointerInputChange {
+): PointerInputChange? {
     var pointer = pointerId
     while (true) {
         val event = awaitPointerEvent()
-        val dragEvent = event.changes.fastFirstOrNull { it.id == pointer }!!
+        val dragEvent = event.changes.fastFirstOrNull { it.id == pointer } ?: return null
         if (dragEvent.changedToUpIgnoreConsumed()) {
             val otherDown = event.changes.fastFirstOrNull { it.pressed }
             if (otherDown == null) {
@@ -705,7 +708,7 @@
 
     while (true) {
         val event = awaitPointerEvent()
-        val dragEvent = event.changes.fastFirstOrNull { it.id == pointer }!!
+        val dragEvent = event.changes.fastFirstOrNull { it.id == pointer } ?: return null
         if (dragEvent.positionChangeConsumed()) {
             return null
         } else if (dragEvent.changedToUpIgnoreConsumed()) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridDsl.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridDsl.kt
index 6c30040..13c37e4 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridDsl.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridDsl.kt
@@ -303,7 +303,7 @@
 /**
  * Receiver scope which is used by [LazyVerticalGrid].
  */
-interface LazyGridScope {
+sealed interface LazyGridScope {
     /**
      * Adds a single item to the scope.
      *
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemInfo.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemInfo.kt
index 37ebdd2..67c8086 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemInfo.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemInfo.kt
@@ -24,7 +24,7 @@
  *
  * @see LazyGridLayoutInfo
  */
-interface LazyGridItemInfo {
+sealed interface LazyGridItemInfo {
     /**
      * The index of the item in the grid.
      */
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemScope.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemScope.kt
index 3aa107f..cb26f21 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemScope.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemScope.kt
@@ -29,7 +29,7 @@
  * Receiver scope being used by the item content parameter of [LazyVerticalGrid].
  */
 @Stable
-interface LazyGridItemScope {
+sealed interface LazyGridItemScope {
     /**
      * This modifier animates the item placement within the Lazy grid.
      *
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridLayoutInfo.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridLayoutInfo.kt
index 023a72a..6dffac7 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridLayoutInfo.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridLayoutInfo.kt
@@ -25,7 +25,7 @@
  *
  * Use [LazyGridState.layoutInfo] to retrieve this
  */
-interface LazyGridLayoutInfo {
+sealed interface LazyGridLayoutInfo {
     /**
      * The list of [LazyGridItemInfo] representing all the currently visible items.
      */
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSpan.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSpan.kt
index 0df925f..794ae1d 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSpan.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridSpan.kt
@@ -42,7 +42,7 @@
 /**
  * Scope of lambdas used to calculate the spans of items in lazy grids.
  */
-interface LazyGridItemSpanScope {
+sealed interface LazyGridItemSpanScope {
     /**
      * The max current line (horizontal for vertical grids) the item can occupy, such that
      * it will be positioned on the current line.
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
index 1ba93dd..6b9c9b4 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
@@ -557,7 +557,8 @@
         current.overflow != overflow ||
         current.maxLines != maxLines ||
         current.density != density ||
-        current.placeholders != placeholders
+        current.placeholders != placeholders ||
+        current.fontFamilyResolver !== fontFamilyResolver
     ) {
         TextDelegate(
             text = text,
@@ -592,7 +593,8 @@
         current.softWrap != softWrap ||
         current.overflow != overflow ||
         current.maxLines != maxLines ||
-        current.density != density
+        current.density != density ||
+        current.fontFamilyResolver !== fontFamilyResolver
     ) {
         TextDelegate(
             text = AnnotatedString(text),
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/DragGestureDetectorTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/DragGestureDetectorTest.kt
index 87de79a..5eb07409 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/DragGestureDetectorTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/DragGestureDetectorTest.kt
@@ -475,6 +475,36 @@
             assertTrue(endOrder == -1)
         }
     }
+
+    // An error in the pointer input stream should stop the gesture without error.
+    @Test
+    fun interruptedBeforeDrag() = util.executeInComposition {
+        down()
+        clearPointerStream()
+        // The next stream doesn't have the existing pointer, so we lose the dragging
+        down().up()
+        assertFalse(gestureStarted)
+    }
+
+    // An error in the pointer input stream should stop the gesture without error.
+    @Test
+    fun interruptedBeforeTouchSlop() = util.executeInComposition {
+        down().moveBy(dragMotion / 2f)
+        clearPointerStream()
+        // The next stream doesn't have the existing pointer, so we lose the dragging
+        down().up()
+        assertFalse(gestureStarted)
+    }
+
+    // An error in the pointer input stream should end in a drag cancellation.
+    @Test
+    fun interruptedAfterTouchSlop() = util.executeInComposition {
+        down().moveBy(dragMotion * 2f)
+        clearPointerStream()
+        // The next stream doesn't have the existing pointer, so we lose the dragging
+        down().up()
+        assertTrue(gestureCanceled)
+    }
 }
 
 @RunWith(JUnit4::class)
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt
index 152d737..1dd5226 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt
@@ -252,6 +252,14 @@
     )
 
     /**
+     * Removes all pointers from the active pointers. This can simulate a faulty pointer stream
+     * for robustness testing.
+     */
+    fun clearPointerStream() {
+        activePointers.clear()
+    }
+
+    /**
      * Updates all changes so that all events are at the current time.
      */
     private fun updateCurrentTime() {
diff --git a/compose/lint/common/src/main/java/androidx/compose/lint/KotlinMetadataUtils.kt b/compose/lint/common/src/main/java/androidx/compose/lint/KotlinMetadataUtils.kt
index 6e751b5..a907370 100644
--- a/compose/lint/common/src/main/java/androidx/compose/lint/KotlinMetadataUtils.kt
+++ b/compose/lint/common/src/main/java/androidx/compose/lint/KotlinMetadataUtils.kt
@@ -118,9 +118,23 @@
     // Strip any mangled part of the name in case of inline classes
     val expectedName = method.name.substringBefore("-")
     val expectedSignature = ClassUtil.getAsmMethodSignature(method)
+    // Since Kotlin 1.6 PSI updates, in some cases what used to be `void` return types are converted
+    // to `kotlin.Unit`, even though in the actual metadata they are still void. Try to match those
+    // cases as well
+    val unitReturnTypeSuffix = "Lkotlin/Unit;"
+    val expectedSignatureConvertedFromUnitToVoid = if (
+        expectedSignature.endsWith(unitReturnTypeSuffix)
+    ) {
+        expectedSignature.substringBeforeLast(unitReturnTypeSuffix) + "V"
+    } else {
+        expectedSignature
+    }
 
     return functions.find {
-        it.name == expectedName && it.signature?.desc == expectedSignature
+        it.name == expectedName && (
+            it.signature?.desc == expectedSignature ||
+                it.signature?.desc == expectedSignatureConvertedFromUnitToVoid
+        )
     }
 }
 
diff --git a/compose/lint/common/src/main/java/androidx/compose/lint/PsiUtils.kt b/compose/lint/common/src/main/java/androidx/compose/lint/PsiUtils.kt
index 5fce565..0485114 100644
--- a/compose/lint/common/src/main/java/androidx/compose/lint/PsiUtils.kt
+++ b/compose/lint/common/src/main/java/androidx/compose/lint/PsiUtils.kt
@@ -34,7 +34,16 @@
  * Whether this [PsiMethod] returns Unit
  */
 val PsiMethod.returnsUnit
-    get() = returnType == PsiType.VOID
+    get() = returnType.isVoidOrUnit
+
+/**
+ * Whether this [PsiType] is `void` or [Unit]
+ *
+ * In Kotlin 1.6 some expressions now explicitly return [Unit] instead of just being [PsiType.VOID],
+ * so this returns whether this type is either.
+ */
+val PsiType?.isVoidOrUnit
+    get() = this == PsiType.VOID || this?.canonicalText == "kotlin.Unit"
 
 /**
  * @return whether [this] inherits from [name]. Returns `true` if [this] _is_ directly [name].
diff --git a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt
index 7d38885..c96667d 100644
--- a/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt
+++ b/compose/lint/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt
@@ -29,7 +29,6 @@
 import com.android.tools.lint.detector.api.Detector
 import com.android.tools.lint.detector.api.Issue
 import org.intellij.lang.annotations.Language
-import org.junit.Ignore
 import org.junit.runners.Parameterized
 
 /* ktlint-disable max-line-length */
@@ -114,7 +113,6 @@
             .run()
     }
 
-    @Ignore("b/223287425")
     @Test
     fun warnsForSingleExpressions() {
         check(
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index cc7ae44..bea3208 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -227,14 +227,16 @@
 
   public final class MaterialTheme {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.ColorScheme getColorScheme();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Shapes getShapes();
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Typography getTypography();
     property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.ColorScheme colorScheme;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Shapes shapes;
     property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Typography typography;
     field public static final androidx.compose.material3.MaterialTheme INSTANCE;
   }
 
   public final class MaterialThemeKt {
-    method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.compose.material3.ColorScheme colorScheme, optional androidx.compose.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.compose.material3.ColorScheme colorScheme, optional androidx.compose.material3.Shapes shapes, optional androidx.compose.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class MenuDefaults {
@@ -324,6 +326,32 @@
   public final class ScaffoldKt {
   }
 
+  @androidx.compose.runtime.Immutable public final class Shapes {
+    ctor public Shapes(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.material3.Shapes copy(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+    method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+    method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraLarge;
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraSmall;
+    property public final androidx.compose.foundation.shape.CornerBasedShape large;
+    property public final androidx.compose.foundation.shape.CornerBasedShape medium;
+    property public final androidx.compose.foundation.shape.CornerBasedShape small;
+    field public static final androidx.compose.material3.Shapes.Companion Companion;
+  }
+
+  public static final class Shapes.Companion {
+    method public androidx.compose.foundation.shape.RoundedCornerShape getFull();
+    method public androidx.compose.ui.graphics.Shape getNone();
+    property public final androidx.compose.foundation.shape.RoundedCornerShape Full;
+    property public final androidx.compose.ui.graphics.Shape None;
+  }
+
+  public final class ShapesKt {
+  }
+
   @androidx.compose.runtime.Stable public interface SliderColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> thumbColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> tickColor(boolean enabled, boolean active);
diff --git a/compose/material3/material3/api/public_plus_experimental_current.txt b/compose/material3/material3/api/public_plus_experimental_current.txt
index 54bb9eb..e072c12 100644
--- a/compose/material3/material3/api/public_plus_experimental_current.txt
+++ b/compose/material3/material3/api/public_plus_experimental_current.txt
@@ -290,14 +290,16 @@
 
   public final class MaterialTheme {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.ColorScheme getColorScheme();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Shapes getShapes();
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Typography getTypography();
     property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.ColorScheme colorScheme;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Shapes shapes;
     property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Typography typography;
     field public static final androidx.compose.material3.MaterialTheme INSTANCE;
   }
 
   public final class MaterialThemeKt {
-    method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.compose.material3.ColorScheme colorScheme, optional androidx.compose.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.compose.material3.ColorScheme colorScheme, optional androidx.compose.material3.Shapes shapes, optional androidx.compose.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class MenuDefaults {
@@ -409,6 +411,32 @@
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void Scaffold(optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional long containerColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
   }
 
+  @androidx.compose.runtime.Immutable public final class Shapes {
+    ctor public Shapes(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.material3.Shapes copy(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+    method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+    method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraLarge;
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraSmall;
+    property public final androidx.compose.foundation.shape.CornerBasedShape large;
+    property public final androidx.compose.foundation.shape.CornerBasedShape medium;
+    property public final androidx.compose.foundation.shape.CornerBasedShape small;
+    field public static final androidx.compose.material3.Shapes.Companion Companion;
+  }
+
+  public static final class Shapes.Companion {
+    method public androidx.compose.foundation.shape.RoundedCornerShape getFull();
+    method public androidx.compose.ui.graphics.Shape getNone();
+    property public final androidx.compose.foundation.shape.RoundedCornerShape Full;
+    property public final androidx.compose.ui.graphics.Shape None;
+  }
+
+  public final class ShapesKt {
+  }
+
   @androidx.compose.runtime.Stable public interface SliderColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> thumbColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> tickColor(boolean enabled, boolean active);
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index cc7ae44..bea3208 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -227,14 +227,16 @@
 
   public final class MaterialTheme {
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.ColorScheme getColorScheme();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Shapes getShapes();
     method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.compose.material3.Typography getTypography();
     property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.ColorScheme colorScheme;
+    property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Shapes shapes;
     property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.compose.material3.Typography typography;
     field public static final androidx.compose.material3.MaterialTheme INSTANCE;
   }
 
   public final class MaterialThemeKt {
-    method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.compose.material3.ColorScheme colorScheme, optional androidx.compose.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void MaterialTheme(optional androidx.compose.material3.ColorScheme colorScheme, optional androidx.compose.material3.Shapes shapes, optional androidx.compose.material3.Typography typography, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class MenuDefaults {
@@ -324,6 +326,32 @@
   public final class ScaffoldKt {
   }
 
+  @androidx.compose.runtime.Immutable public final class Shapes {
+    ctor public Shapes(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.material3.Shapes copy(optional androidx.compose.foundation.shape.CornerBasedShape extraSmall, optional androidx.compose.foundation.shape.CornerBasedShape small, optional androidx.compose.foundation.shape.CornerBasedShape medium, optional androidx.compose.foundation.shape.CornerBasedShape large, optional androidx.compose.foundation.shape.CornerBasedShape extraLarge);
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getExtraSmall();
+    method public androidx.compose.foundation.shape.CornerBasedShape getLarge();
+    method public androidx.compose.foundation.shape.CornerBasedShape getMedium();
+    method public androidx.compose.foundation.shape.CornerBasedShape getSmall();
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraLarge;
+    property public final androidx.compose.foundation.shape.CornerBasedShape extraSmall;
+    property public final androidx.compose.foundation.shape.CornerBasedShape large;
+    property public final androidx.compose.foundation.shape.CornerBasedShape medium;
+    property public final androidx.compose.foundation.shape.CornerBasedShape small;
+    field public static final androidx.compose.material3.Shapes.Companion Companion;
+  }
+
+  public static final class Shapes.Companion {
+    method public androidx.compose.foundation.shape.RoundedCornerShape getFull();
+    method public androidx.compose.ui.graphics.Shape getNone();
+    property public final androidx.compose.foundation.shape.RoundedCornerShape Full;
+    property public final androidx.compose.ui.graphics.Shape None;
+  }
+
+  public final class ShapesKt {
+  }
+
   @androidx.compose.runtime.Stable public interface SliderColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> thumbColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> tickColor(boolean enabled, boolean active);
diff --git a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/Material3Demos.kt b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/Material3Demos.kt
index 30e5eba..963cac0 100644
--- a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/Material3Demos.kt
+++ b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/Material3Demos.kt
@@ -23,5 +23,6 @@
     "Material 3",
     listOf(
         ComposableDemo("Color Scheme") { ColorSchemeDemo() },
-    )
+        ComposableDemo("Shape") { ShapeDemo() },
+    ),
 )
diff --git a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/ShapeDemos.kt b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/ShapeDemos.kt
new file mode 100644
index 0000000..6c8ed23
--- /dev/null
+++ b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/ShapeDemos.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.material3.demos
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.Button
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Shapes
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun ShapeDemo() {
+    val shapes = MaterialTheme.shapes
+    Column(
+        horizontalAlignment = Alignment.CenterHorizontally,
+        modifier = Modifier.verticalScroll(rememberScrollState()),
+    ) {
+        Button(shape = Shapes.None, onClick = {}) { Text("None") }
+        Spacer(modifier = Modifier.height(16.dp))
+        Button(shape = shapes.extraSmall, onClick = {}) { Text("Extra  Small") }
+        Spacer(modifier = Modifier.height(16.dp))
+        Button(shape = shapes.small, onClick = {}) { Text("Small") }
+        Spacer(modifier = Modifier.height(16.dp))
+        Button(shape = shapes.medium, onClick = {}) { Text("Medium") }
+        Spacer(modifier = Modifier.height(16.dp))
+        Button(shape = shapes.large, onClick = {}) { Text("Large") }
+        Spacer(modifier = Modifier.height(16.dp))
+        Button(shape = shapes.extraLarge, onClick = {}) { Text("Extra Large") }
+        Spacer(modifier = Modifier.height(16.dp))
+        Button(shape = Shapes.Full, onClick = {}) { Text("Full") }
+    }
+}
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ShapesScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ShapesScreenshotTest.kt
new file mode 100644
index 0000000..fe1fb3b
--- /dev/null
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ShapesScreenshotTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.compose.material3
+
+import android.os.Build
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@OptIn(ExperimentalTestApi::class, ExperimentalMaterial3Api::class)
+class ShapesScreenshotTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(GOLDEN_MATERIAL3)
+
+    @Test
+    fun shapes() {
+        rule.setMaterialContent(lightColorScheme()) {
+            Box(Modifier.semantics(mergeDescendants = true) {}.testTag(Tag)) {
+                val shapes = MaterialTheme.shapes
+                Column(
+                    horizontalAlignment = Alignment.CenterHorizontally,
+                    modifier = Modifier.verticalScroll(rememberScrollState()),
+                ) {
+                    Button(shape = Shapes.None, onClick = {}) { Text("None") }
+                    Spacer(modifier = Modifier.height(16.dp))
+                    Button(shape = shapes.extraSmall, onClick = {}) { Text("Extra  Small") }
+                    Spacer(modifier = Modifier.height(16.dp))
+                    Button(shape = shapes.small, onClick = {}) { Text("Small") }
+                    Spacer(modifier = Modifier.height(16.dp))
+                    Button(shape = shapes.medium, onClick = {}) { Text("Medium") }
+                    Spacer(modifier = Modifier.height(16.dp))
+                    Button(shape = shapes.large, onClick = {}) { Text("Large") }
+                    Spacer(modifier = Modifier.height(16.dp))
+                    Button(shape = shapes.extraLarge, onClick = {}) { Text("Extra Large") }
+                    Spacer(modifier = Modifier.height(16.dp))
+                    Button(shape = Shapes.Full, onClick = {}) { Text("Full") }
+                }
+            }
+        }
+        assertAgainstGolden("shapes")
+    }
+
+    private fun assertAgainstGolden(goldenName: String) {
+        rule.onNodeWithTag(Tag)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, goldenName)
+    }
+
+    private val Tag = "Shapes"
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/MaterialTheme.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/MaterialTheme.kt
index d528c18..ba5b73b 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/MaterialTheme.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/MaterialTheme.kt
@@ -50,11 +50,13 @@
  *
  * @param colorScheme A complete definition of the Material Color theme for this hierarchy
  * @param typography A set of text styles to be used as this hierarchy's typography system
+ * @param shapes A set of corner shapes to be used as this hierarchy's shape system
  */
 
 @Composable
 fun MaterialTheme(
     colorScheme: ColorScheme = MaterialTheme.colorScheme,
+    shapes: Shapes = MaterialTheme.shapes,
     typography: Typography = MaterialTheme.typography,
     content: @Composable () -> Unit
 ) {
@@ -70,8 +72,8 @@
         LocalColorScheme provides rememberedColorScheme,
         LocalIndication provides rippleIndication,
         LocalRippleTheme provides MaterialRippleTheme,
+        LocalShapes provides shapes,
         LocalTypography provides typography,
-
     ) {
         ProvideTextStyle(value = typography.bodyLarge, content = content)
     }
@@ -97,6 +99,14 @@
         @Composable
         @ReadOnlyComposable
         get() = LocalTypography.current
+
+    /**
+     * Retrieves the current [Shapes] at the call site's position in the hierarchy.
+     */
+    val shapes: Shapes
+        @Composable
+        @ReadOnlyComposable
+        get() = LocalShapes.current
 }
 
 @Immutable
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Shapes.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Shapes.kt
new file mode 100644
index 0000000..6abd1e2
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Shapes.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.material3
+
+import androidx.compose.foundation.shape.CornerBasedShape
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.material3.tokens.ShapeKeyTokens
+import androidx.compose.material3.tokens.ShapeTokens
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.staticCompositionLocalOf
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.dp
+
+/**
+ * Material surfaces can be displayed in different shapes. Shapes direct attention, identify
+ * components, communicate state, and express brand.
+ *
+ * There are different sizes of shapes:
+ * - Extra Small
+ * - Small
+ * - Medium
+ * - Large
+ * - Extra Large
+ *
+ * You can customize the shape system for all components in the [MaterialTheme] or you can do it
+ * on a per component basis.
+ *
+ * Shape refers to the corners of a component. You can change the shape that a component has
+ * by overriding the shape parameter for that component. For example, by default, buttons use the
+ * shape style “full.” If your product requires a smaller amount of roundedness, you can override
+ * the shape parameter with a different shape value like [MaterialTheme.shapes.small].
+ *
+ * @param extraSmall A shape style with 4 same-sized corners whose size are bigger than
+ * [Shapes.None] and smaller than [Shapes.small]. By default autocomplete menu, select menu,
+ * snackbars, standard menu, and text fields use this shape.
+ * @param small A shape style with 4 same-sized corners whose size are bigger than
+ * [Shapes.extraSmall] and smaller than [Shapes.medium]. By default chips use this shape.
+ * @param medium A shape style with 4 same-sized corners whose size are bigger than [Shapes.small]
+ * and smaller than [Shapes.large]. By default cards and small FABs use this shape.
+ * @param large A shape style with 4 same-sized corners whose size are bigger than [Shapes.medium]
+ * and smaller than [Shapes.extraLarge]. By default extended FABs, FABs, and navigation drawers use
+ * this shape.
+ * @param extraLarge A shape style with 4 same-sized corners whose size are bigger than
+ * [Shapes.large] and smaller than [Shapes.Full]. By default large FABs use this shape.
+ */
+@Immutable
+class Shapes(
+    val extraSmall: CornerBasedShape = ShapeTokens.CornerExtraSmall,
+    val small: CornerBasedShape = ShapeTokens.CornerSmall,
+    val medium: CornerBasedShape = ShapeTokens.CornerMedium,
+    val large: CornerBasedShape = ShapeTokens.CornerLarge,
+    val extraLarge: CornerBasedShape = ShapeTokens.CornerExtraLarge,
+) {
+    companion object {
+        /** A shape with no rounded corners (a rectangle shape). */
+        val None = ShapeTokens.CornerNone
+
+        /** A shape with fully extended rounded corners (a circular shape). */
+        val Full = ShapeTokens.CornerFull
+    }
+
+    /** Returns a copy of this Shapes, optionally overriding some of the values. */
+    fun copy(
+        extraSmall: CornerBasedShape = this.extraSmall,
+        small: CornerBasedShape = this.small,
+        medium: CornerBasedShape = this.medium,
+        large: CornerBasedShape = this.large,
+        extraLarge: CornerBasedShape = this.extraLarge,
+    ): Shapes = Shapes(
+        extraSmall = extraSmall,
+        small = small,
+        medium = medium,
+        large = large,
+        extraLarge = extraLarge,
+    )
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Shapes) return false
+        if (extraSmall != other.extraSmall) return false
+        if (small != other.small) return false
+        if (medium != other.medium) return false
+        if (large != other.large) return false
+        if (extraLarge != other.extraLarge) return false
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = extraSmall.hashCode()
+        result = 31 * result + small.hashCode()
+        result = 31 * result + medium.hashCode()
+        result = 31 * result + large.hashCode()
+        result = 31 * result + extraLarge.hashCode()
+        return result
+    }
+
+    override fun toString(): String {
+        return "Shapes(" +
+            "extraSmall=$extraSmall, " +
+            "small=$small, " +
+            "medium=$medium, " +
+            "large=$large, " +
+            "extraLarge=$extraLarge)"
+    }
+}
+
+/** Helper function for component shape tokens. Used to grab the top values of a shape parameter. */
+internal fun CornerBasedShape.top(): CornerBasedShape {
+    return copy(bottomStart = CornerSize(0.0.dp), bottomEnd = CornerSize(0.0.dp))
+}
+
+/** Helper function for component shape tokens. Used to grab the end values of a shape parameter. */
+internal fun CornerBasedShape.end(): CornerBasedShape {
+    return copy(topStart = CornerSize(0.0.dp), bottomStart = CornerSize(0.0.dp))
+}
+
+/**
+ * Helper function for component shape tokens. Here is an example on how to use component color
+ * tokens:
+ * ``MaterialTheme.shapes.fromToken(FabPrimarySmallTokens.ContainerShape)``
+ */
+internal fun Shapes.fromToken(value: ShapeKeyTokens): Shape {
+    return when (value) {
+        ShapeKeyTokens.CornerExtraLarge -> extraLarge
+        ShapeKeyTokens.CornerExtraLargeTop -> extraLarge.top()
+        ShapeKeyTokens.CornerExtraSmall -> extraSmall
+        ShapeKeyTokens.CornerExtraSmallTop -> extraSmall.top()
+        ShapeKeyTokens.CornerFull -> Shapes.Full
+        ShapeKeyTokens.CornerLarge -> large
+        ShapeKeyTokens.CornerLargeEnd -> large.end()
+        ShapeKeyTokens.CornerLargeTop -> large.top()
+        ShapeKeyTokens.CornerMedium -> medium
+        ShapeKeyTokens.CornerNone -> Shapes.None
+        ShapeKeyTokens.CornerSmall -> small
+    }
+}
+
+/** Converts a shape token key to the local shape provided by the theme */
+@Composable
+internal fun ShapeKeyTokens.toShape(): Shape {
+    return MaterialTheme.shapes.fromToken(this)
+}
+
+/** CompositionLocal used to specify the default shapes for the surfaces. */
+internal val LocalShapes = staticCompositionLocalOf { Shapes() }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ShapeKeyTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ShapeKeyTokens.kt
new file mode 100644
index 0000000..ee94ad5
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ShapeKeyTokens.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// VERSION: v0_85
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.compose.material3.tokens
+
+internal enum class ShapeKeyTokens {
+    CornerExtraLarge,
+    CornerExtraLargeTop,
+    CornerExtraSmall,
+    CornerExtraSmallTop,
+    CornerFull,
+    CornerLarge,
+    CornerLargeEnd,
+    CornerLargeTop,
+    CornerMedium,
+    CornerNone,
+    CornerSmall,
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ShapeTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ShapeTokens.kt
index c0034a0..1955f53 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ShapeTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/ShapeTokens.kt
@@ -13,15 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-// VERSION: v0_76
+// VERSION: v0_85
 // GENERATED CODE - DO NOT MODIFY BY HAND
-
 package androidx.compose.material3.tokens
-
 import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.ui.graphics.RectangleShape
 import androidx.compose.ui.unit.dp
-
 internal object ShapeTokens {
     val CornerExtraLarge = RoundedCornerShape(28.0.dp)
     val CornerExtraLargeTop =
@@ -55,6 +53,6 @@
             bottomStart = 0.0.dp
         )
     val CornerMedium = RoundedCornerShape(12.0.dp)
-    val CornerNone = RoundedCornerShape(0.0.dp)
+    val CornerNone = RectangleShape
     val CornerSmall = RoundedCornerShape(8.0.dp)
 }
diff --git a/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/RememberDetector.kt b/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/RememberDetector.kt
index 966e6ea..6e0f585 100644
--- a/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/RememberDetector.kt
+++ b/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/RememberDetector.kt
@@ -20,6 +20,7 @@
 
 import androidx.compose.lint.Names
 import androidx.compose.lint.isInPackageName
+import androidx.compose.lint.isVoidOrUnit
 import com.android.tools.lint.detector.api.Category
 import com.android.tools.lint.detector.api.Detector
 import com.android.tools.lint.detector.api.Implementation
@@ -29,7 +30,6 @@
 import com.android.tools.lint.detector.api.Severity
 import com.android.tools.lint.detector.api.SourceCodeScanner
 import com.intellij.psi.PsiMethod
-import com.intellij.psi.PsiType
 import org.jetbrains.uast.UCallExpression
 import java.util.EnumSet
 
@@ -41,7 +41,7 @@
 
     override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
         if (method.isInPackageName(Names.Runtime.PackageName)) {
-            if (node.getExpressionType() == PsiType.VOID) {
+            if (node.getExpressionType().isVoidOrUnit) {
                 context.report(
                     RememberReturnType,
                     node,
diff --git a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/RememberDetectorTest.kt b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/RememberDetectorTest.kt
index 34c5a13..4fa7427 100644
--- a/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/RememberDetectorTest.kt
+++ b/compose/runtime/runtime-lint/src/test/java/androidx/compose/runtime/lint/RememberDetectorTest.kt
@@ -22,7 +22,6 @@
 import com.android.tools.lint.checks.infrastructure.LintDetectorTest
 import com.android.tools.lint.detector.api.Detector
 import com.android.tools.lint.detector.api.Issue
-import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -39,7 +38,6 @@
     override fun getIssues(): MutableList<Issue> =
         mutableListOf(RememberDetector.RememberReturnType)
 
-    @Ignore("b/223287425")
     @Test
     fun returnsUnit() {
         lint().files(
@@ -123,9 +121,6 @@
             Stubs.Composable,
             Stubs.Remember
         )
-            // TODO: incorrect missing import warning, because androidx.compose.runtime.remember
-            //  resolves to multiple functions. Remove when this is fixed in a future Lint version
-            .allowCompilationErrors()
             .run()
             .expect(
                 """
@@ -164,7 +159,6 @@
             )
     }
 
-    @Ignore("b/223287425")
     @Test
     fun returnsValue_explicitUnitType() {
         lint().files(
@@ -248,9 +242,6 @@
             Stubs.Composable,
             Stubs.Remember
         )
-            // TODO: incorrect missing import warning, because androidx.compose.runtime.remember
-            //  resolves to multiple functions. Remove when this is fixed in a future Lint version
-            .allowCompilationErrors()
             .run()
             .expect(
                 """
@@ -362,9 +353,6 @@
             Stubs.Composable,
             Stubs.Remember
         )
-            // TODO: incorrect missing import warning, because androidx.compose.runtime.remember
-            //  resolves to multiple functions. Remove when this is fixed in a future Lint version
-            .allowCompilationErrors()
             .run()
             .expectClean()
     }
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
index c223ed9..b69dbac 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
@@ -28,5 +28,5 @@
      * IMPORTANT: Whenever updating this value, please make sure to also update `versionTable` and
      * `minimumRuntimeVersionInt` in `VersionChecker.kt` of the compiler.
      */
-    const val version: Int = 6500
+    const val version: Int = 6600
 }
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/LayoutCoordinatesHelperTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/LayoutCoordinatesHelperTest.kt
index 5658dce..45010ba 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/LayoutCoordinatesHelperTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/LayoutCoordinatesHelperTest.kt
@@ -28,7 +28,6 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
-import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.layout.LayoutCoordinates
@@ -52,13 +51,14 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertTrue
+import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
 
 @MediumTest
 @RunWith(AndroidJUnit4::class)
@@ -132,7 +132,6 @@
         )
     }
 
-    @OptIn(ExperimentalComposeUiApi::class)
     @Test
     fun onPlaced_alignmentChange() {
         var offset by mutableStateOf(IntOffset(0, 0))
@@ -165,7 +164,7 @@
         }
     }
 
-    @OptIn(ExperimentalComposeUiApi::class)
+    @Ignore("b/225198728")
     @Test
     fun onPlaced_invocation() {
         var additionalOffset by mutableStateOf(IntOffset.Zero)
@@ -190,21 +189,15 @@
             }
         }
         rule.runOnIdle {
-            invocations.forEach {
-                assertEquals(1, it)
-            }
+            assertThat(invocations).containsExactlyElementsIn(listOf(1, 1, 1))
             alignment = Alignment.TopStart
         }
         rule.runOnIdle {
-            invocations.forEach {
-                assertEquals(2, it)
-            }
+            assertThat(invocations).containsExactlyElementsIn(listOf(2, 2, 2))
             additionalOffset = IntOffset(0, 10)
         }
         rule.runOnIdle {
-            invocations.forEach {
-                assertEquals(3, it)
-            }
+            assertThat(invocations).containsExactlyElementsIn(listOf(3, 3, 3))
         }
     }
 
@@ -239,7 +232,6 @@
         }
     }
 
-    @OptIn(ExperimentalComposeUiApi::class)
     private fun LayoutCoordinates.placementInParent() =
         parentCoordinates!!.localPositionOf(this, Offset.Zero).round()
 }
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/assertions/BoundsAssertionsTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/assertions/BoundsAssertionsTest.kt
index f72f8bf..a8d56b1 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/assertions/BoundsAssertionsTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/assertions/BoundsAssertionsTest.kt
@@ -25,7 +25,9 @@
 import androidx.compose.foundation.layout.requiredSize
 import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.testutils.WithMinimumTouchTargetSize
+import androidx.compose.testutils.assertIsEqualTo
 import androidx.compose.testutils.expectError
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -33,7 +35,9 @@
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.HorizontalAlignmentLine
 import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.assertHeightIsAtLeast
 import androidx.compose.ui.test.assertHeightIsEqualTo
 import androidx.compose.ui.test.assertLeftPositionInRootIsEqualTo
@@ -44,9 +48,11 @@
 import androidx.compose.ui.test.assertWidthIsAtLeast
 import androidx.compose.ui.test.assertWidthIsEqualTo
 import androidx.compose.ui.test.getAlignmentLinePosition
+import androidx.compose.ui.test.getBoundsInRoot
 import androidx.compose.ui.test.getUnclippedBoundsInRoot
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
@@ -232,6 +238,7 @@
     fun assertClippedPosition() {
         composeClippedBox()
 
+        // Node is clipped, but position should be unaffected
         rule.onNodeWithTag(tag)
             .assertPositionInRootIsEqualTo(expectedLeft = (-30).dp, expectedTop = (-10).dp)
             .assertLeftPositionInRootIsEqualTo((-30).dp)
@@ -242,6 +249,7 @@
     fun assertClippedSize() {
         composeClippedBox()
 
+        // Node is clipped, but width and height should be unaffected
         rule.onNodeWithTag(tag)
             .assertWidthIsEqualTo(80.dp)
             .assertHeightIsEqualTo(100.dp)
@@ -258,6 +266,103 @@
     }
 
     @Test
+    fun assertSizeUsesLocalDensity() {
+        rule.setContent {
+            SmallBox(tag = "default-density")
+            CompositionLocalProvider(LocalDensity provides Density(1f, 1f)) {
+                SmallBox(tag = "low-density")
+            }
+            CompositionLocalProvider(LocalDensity provides Density(4f, 1f)) {
+                SmallBox(tag = "high-density")
+            }
+        }
+
+        fun SemanticsNodeInteraction.verifySize() {
+            assertWidthIsEqualTo(10.dp)
+            assertHeightIsEqualTo(10.dp)
+        }
+
+        rule.onNodeWithTag("default-density").verifySize()
+        rule.onNodeWithTag("low-density").verifySize()
+        rule.onNodeWithTag("high-density").verifySize()
+    }
+
+    @Composable
+    private fun TouchTargetTestContent(tag: String) {
+        WithMinimumTouchTargetSize(DpSize(20.dp, 20.dp)) {
+            SmallBox(Modifier.clickable {}, tag)
+        }
+    }
+
+    @Test
+    fun assertTouchSizeUsesLocalDensity() {
+        rule.setContent {
+            TouchTargetTestContent("default-density")
+            CompositionLocalProvider(LocalDensity provides Density(1f, 1f)) {
+                TouchTargetTestContent("low-density")
+            }
+            CompositionLocalProvider(LocalDensity provides Density(4f, 1f)) {
+                TouchTargetTestContent("high-density")
+            }
+        }
+
+        fun SemanticsNodeInteraction.verifyTouchSize() {
+            assertTouchWidthIsEqualTo(20.dp)
+            assertTouchHeightIsEqualTo(20.dp)
+        }
+
+        rule.onNodeWithTag("default-density").verifyTouchSize()
+        rule.onNodeWithTag("low-density").verifyTouchSize()
+        rule.onNodeWithTag("high-density").verifyTouchSize()
+    }
+
+    @Test
+    fun assertBoundsInRootUsesLocalDensity() {
+        rule.setContent {
+            SmallBox(Modifier.padding(20.dp), "default-density")
+            CompositionLocalProvider(LocalDensity provides Density(1f, 1f)) {
+                SmallBox(Modifier.padding(20.dp), "low-density")
+            }
+            CompositionLocalProvider(LocalDensity provides Density(4f, 1f)) {
+                SmallBox(Modifier.padding(20.dp), "high-density")
+            }
+        }
+
+        fun SemanticsNodeInteraction.verifyBoundsInRoot() {
+            getBoundsInRoot()
+                .let {
+                    it.left.assertIsEqualTo(20.dp)
+                    it.top.assertIsEqualTo(20.dp)
+                }
+        }
+
+        rule.onNodeWithTag("default-density").verifyBoundsInRoot()
+        rule.onNodeWithTag("low-density").verifyBoundsInRoot()
+        rule.onNodeWithTag("high-density").verifyBoundsInRoot()
+    }
+
+    @Test
+    fun assertAlignmentLinesUseLocalDensity() {
+        rule.setContent {
+            BoxWithAlignmentLine(Modifier.testTag("default-density"))
+            CompositionLocalProvider(LocalDensity provides Density(1f, 1f)) {
+                BoxWithAlignmentLine(Modifier.testTag("low-density"))
+            }
+            CompositionLocalProvider(LocalDensity provides Density(4f, 1f)) {
+                BoxWithAlignmentLine(Modifier.testTag("high-density"))
+            }
+        }
+
+        fun SemanticsNodeInteraction.verifyAlignmentLine() {
+            getAlignmentLinePosition(TestLine).assertIsEqualTo(TestLinePosition)
+        }
+
+        rule.onNodeWithTag("default-density").verifyAlignmentLine()
+        rule.onNodeWithTag("low-density").verifyAlignmentLine()
+        rule.onNodeWithTag("high-density").verifyAlignmentLine()
+    }
+
+    @Test
     fun getPosition_notMeasuredNotPlaced() {
         // When we have a node that is not measure and not placed
         getPositionTest {
@@ -349,7 +454,7 @@
     @Test
     fun getAlignmentLine_measuredNotPlaced() {
         // When we have a node with an alignment line that is measured but not placed
-        getAlignmentLineTest(expectedPosition = with(rule.density) { TestLinePosition.toDp() }) {
+        getAlignmentLineTest(expectedPosition = TestLinePosition) {
             DoNotPlace {
                 BoxWithAlignmentLine(Modifier.testTag(tag))
             }
@@ -371,8 +476,9 @@
         rule.setContent(content)
 
         // Then we can still query the alignment line
-        assertThat(rule.onNodeWithTag(tag).getAlignmentLinePosition(TestLine))
-            .isEqualTo(expectedPosition)
+        rule.onNodeWithTag(tag)
+            .getAlignmentLinePosition(TestLine)
+            .assertIsEqualTo(expectedPosition)
     }
 
     @Composable
@@ -390,16 +496,17 @@
         }
     }
 
-    private val TestLinePosition = 30
+    private val TestLinePosition = 10.dp
     private val TestLine = HorizontalAlignmentLine(::max)
 
     @Composable
-    private fun BoxWithAlignmentLine(modifier: Modifier) {
+    private fun BoxWithAlignmentLine(modifier: Modifier, linePosition: Dp = TestLinePosition) {
+        val linePositionPx = with(LocalDensity.current) { linePosition.roundToPx() }
         Layout({}, modifier) { _, constraints ->
             layout(
                 constraints.maxWidth,
                 constraints.maxHeight,
-                mapOf(TestLine to TestLinePosition)
+                mapOf(TestLine to linePositionPx)
             ) {}
         }
     }
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/BoundsAssertions.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/BoundsAssertions.kt
index a150d1c..a39e576 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/BoundsAssertions.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/BoundsAssertions.kt
@@ -169,7 +169,7 @@
  */
 fun SemanticsNodeInteraction.getBoundsInRoot(): DpRect {
     val node = fetchSemanticsNode("Failed to retrieve bounds of the node.")
-    return with(node.root!!.density) {
+    return with(node.layoutInfo.density) {
         node.boundsInRoot.let {
             DpRect(it.left.toDp(), it.top.toDp(), it.right.toDp(), it.bottom.toDp())
         }
@@ -195,7 +195,7 @@
     operation: Density.(SemanticsNode) -> R
 ): R {
     val node = fetchSemanticsNode("Failed to retrieve density for the node.")
-    val density = node.root!!.density
+    val density = node.layoutInfo.density
     return operation.invoke(density, node)
 }
 
@@ -203,7 +203,7 @@
     assertion: (DpRect) -> Unit
 ): SemanticsNodeInteraction {
     val node = fetchSemanticsNode("Failed to retrieve bounds of the node.")
-    val bounds = with(node.root!!.density) {
+    val bounds = with(node.layoutInfo.density) {
         node.unclippedBoundsInRoot.let {
             DpRect(it.left.toDp(), it.top.toDp(), it.right.toDp(), it.bottom.toDp())
         }
@@ -216,7 +216,7 @@
     assertion: (DpRect) -> Unit
 ): SemanticsNodeInteraction {
     val node = fetchSemanticsNode("Failed to retrieve bounds of the node.")
-    val bounds = with(node.root!!.density) {
+    val bounds = with(node.layoutInfo.density) {
         node.touchBoundsInRoot.let {
             DpRect(it.left.toDp(), it.top.toDp(), it.right.toDp(), it.bottom.toDp())
         }
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index c8aa120..71901ff 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -550,6 +550,9 @@
   public final class AndroidFontLoader_androidKt {
   }
 
+  public final class AndroidFontResolveInterceptor_androidKt {
+  }
+
   public final class AndroidFontUtils_androidKt {
   }
 
diff --git a/compose/ui/ui-text/api/public_plus_experimental_current.txt b/compose/ui/ui-text/api/public_plus_experimental_current.txt
index 604b381..32259b5 100644
--- a/compose/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-text/api/public_plus_experimental_current.txt
@@ -565,6 +565,9 @@
   public final class AndroidFontLoader_androidKt {
   }
 
+  public final class AndroidFontResolveInterceptor_androidKt {
+  }
+
   public final class AndroidFontUtils_androidKt {
   }
 
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index c8aa120..71901ff 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -550,6 +550,9 @@
   public final class AndroidFontLoader_androidKt {
   }
 
+  public final class AndroidFontResolveInterceptor_androidKt {
+  }
+
   public final class AndroidFontUtils_androidKt {
   }
 
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextTestExtensions.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextTestExtensions.kt
index 3458f16..de9bfc3 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextTestExtensions.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextTestExtensions.kt
@@ -27,6 +27,8 @@
 import androidx.compose.ui.text.font.PlatformFontFamilyTypefaceAdapter
 import androidx.compose.ui.text.font.TypefaceRequestCache
 import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.text.font.AndroidFontResolveInterceptor
+import androidx.compose.ui.text.font.PlatformResolveInterceptor
 import kotlin.math.ceil
 import kotlin.math.roundToInt
 
@@ -43,13 +45,18 @@
 @OptIn(ExperimentalTextApi::class)
 internal fun UncachedFontFamilyResolver(
     context: Context
-): FontFamily.Resolver = UncachedFontFamilyResolver(AndroidFontLoader(context))
+): FontFamily.Resolver = UncachedFontFamilyResolver(
+    AndroidFontLoader(context),
+    AndroidFontResolveInterceptor(context)
+)
 
 @OptIn(ExperimentalTextApi::class)
 internal fun UncachedFontFamilyResolver(
-    platformFontLoader: PlatformFontLoader
+    platformFontLoader: PlatformFontLoader,
+    platformResolveInterceptor: PlatformResolveInterceptor
 ): FontFamily.Resolver = FontFamilyResolverImpl(
     platformFontLoader,
+    platformResolveInterceptor,
     TypefaceRequestCache(),
     FontListFontFamilyTypefaceAdapter(AsyncTypefaceCache()),
     PlatformFontFamilyTypefaceAdapter()
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/FontFamilyResolverImplCancellationTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/FontFamilyResolverImplCancellationTest.kt
index 1d1e891..ef79faf8 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/FontFamilyResolverImplCancellationTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/FontFamilyResolverImplCancellationTest.kt
@@ -50,6 +50,7 @@
 
     private val context = InstrumentationRegistry.getInstrumentation().context
     private val fontLoader = AndroidFontLoader(context)
+    private val fontResolveInterceptor = AndroidFontResolveInterceptor(context)
 
     @Before
     fun setup() {
@@ -62,6 +63,7 @@
         val injectedContext = scope.coroutineContext.minusKey(CoroutineExceptionHandler)
         subject = FontFamilyResolverImpl(
             fontLoader,
+            fontResolveInterceptor,
             typefaceRequestCache,
             FontListFontFamilyTypefaceAdapter(asyncTypefaceCache, injectedContext))
         typefaceLoader = AsyncTestTypefaceLoader()
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/FontFamilyResolverImplTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/FontFamilyResolverImplTest.kt
index 68ea243..4d0fad8 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/FontFamilyResolverImplTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/font/FontFamilyResolverImplTest.kt
@@ -22,8 +22,10 @@
 import androidx.compose.ui.text.ExperimentalTextApi
 import androidx.compose.ui.text.FontTestData
 import androidx.compose.ui.text.UncachedFontFamilyResolver
+import androidx.compose.ui.text.font.testutils.AsyncFauxFont
 import androidx.compose.ui.text.font.testutils.AsyncTestTypefaceLoader
 import androidx.compose.ui.text.font.testutils.BlockingFauxFont
+import androidx.compose.ui.text.font.testutils.OptionalFauxFont
 import androidx.compose.ui.text.matchers.assertThat
 import androidx.compose.ui.text.platform.bitmap
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -54,6 +56,8 @@
     private val context = InstrumentationRegistry.getInstrumentation().context
 
     private val fontLoader = AndroidFontLoader(context)
+    // This is the default value that Android uses
+    private val accessibilityFontWeightAdjustment = 300
     private lateinit var subject: FontFamilyResolverImpl
 
     @Before
@@ -62,16 +66,25 @@
         typefaceCache = TypefaceRequestCache()
         dispatcher = UnconfinedTestDispatcher()
         scope = TestScope(dispatcher)
+        initializeSubject()
+        typefaceLoader = AsyncTestTypefaceLoader()
+    }
+
+    private fun initializeSubject(
+        platformResolveInterceptor: PlatformResolveInterceptor =
+            AndroidFontResolveInterceptor(context)
+    ) {
         val injectedContext = scope.coroutineContext.minusKey(CoroutineExceptionHandler)
+
         subject = FontFamilyResolverImpl(
             fontLoader,
+            platformResolveInterceptor = platformResolveInterceptor,
             typefaceRequestCache = typefaceCache,
             fontListFontFamilyTypefaceAdapter = FontListFontFamilyTypefaceAdapter(
                 asyncTypefaceCache,
                 injectedContext
             )
         )
-        typefaceLoader = AsyncTestTypefaceLoader()
     }
 
     private fun resolveAsTypeface(
@@ -428,7 +441,10 @@
             override suspend fun awaitLoad(font: Font): Any = Typeface.DEFAULT
             override val cacheKey: String = "Not the default resource loader"
         }
-        val otherTypeface = UncachedFontFamilyResolver(newFontLoader)
+        val otherTypeface = UncachedFontFamilyResolver(
+            newFontLoader,
+            PlatformResolveInterceptor.Default
+        )
             .resolve(fontFamily).value as Typeface
 
         assertThat(typeface).isNotSameInstanceAs(otherTypeface)
@@ -459,14 +475,17 @@
             }
         )
         val firstAndroidResourceLoader = AndroidFontLoader(context)
+        val androidResolveInterceptor = AndroidFontResolveInterceptor(context)
         val typeface = FontFamilyResolverImpl(
             fontLoader,
+            androidResolveInterceptor,
             typefaceCache,
             FontListFontFamilyTypefaceAdapter(asyncTypefaceCache)
         ).resolve(fontFamily).value as Typeface
         val secondAndroidResourceLoader = AndroidFontLoader(context)
         val otherTypeface = FontFamilyResolverImpl(
             fontLoader,
+            androidResolveInterceptor,
             typefaceCache,
             FontListFontFamilyTypefaceAdapter(asyncTypefaceCache)
         ).resolve(fontFamily).value as Typeface
@@ -599,4 +618,159 @@
         assertThat(typeface500).hasWeightAndStyle(FontWeight.W100, FontStyle.Normal)
         assertThat(typeface600).hasWeightAndStyle(FontWeight.W600, FontStyle.Normal)
     }
+
+    @Test
+    fun androidFontResolveInterceptor_affectsTheFontWeight() {
+        initializeSubject(AndroidFontResolveInterceptor(accessibilityFontWeightAdjustment))
+        val fontFamily = FontFamily(
+            FontTestData.FONT_400_REGULAR,
+            FontTestData.FONT_500_REGULAR,
+            FontTestData.FONT_600_REGULAR,
+            FontTestData.FONT_700_REGULAR,
+            FontTestData.FONT_800_REGULAR
+        )
+        val typeface = resolveAsTypeface(
+            fontFamily = fontFamily,
+            fontWeight = FontWeight.W400
+        )
+
+        assertThat(typeface).hasWeightAndStyle(FontWeight.W700, FontStyle.Normal)
+    }
+
+    @Test
+    fun androidFontResolveInterceptor_doesNotAffectTheFontStyle() {
+        initializeSubject(AndroidFontResolveInterceptor(accessibilityFontWeightAdjustment))
+
+        val typeface = resolveAsTypeface(
+            fontWeight = FontWeight.W400,
+            fontStyle = FontStyle.Italic
+        )
+
+        assertThat(typeface).hasWeightAndStyle(FontWeight.W700, FontStyle.Italic)
+    }
+
+    @Test
+    fun platformResolveInterceptor_affectsTheResolvedFontStyle() {
+        initializeSubject(
+            platformResolveInterceptor = object : PlatformResolveInterceptor {
+                override fun interceptFontStyle(fontStyle: FontStyle) = FontStyle.Italic
+            }
+        )
+
+        val typeface = resolveAsTypeface(
+            fontWeight = FontWeight.Normal,
+            fontStyle = FontStyle.Normal
+        )
+
+        assertThat(typeface).hasWeightAndStyle(FontWeight.Normal, FontStyle.Italic)
+    }
+
+    @Test
+    fun platformResolveInterceptor_affectsTheResolvedFontSynthesis() {
+        initializeSubject(
+            platformResolveInterceptor = object : PlatformResolveInterceptor {
+                override fun interceptFontSynthesis(fontSynthesis: FontSynthesis) =
+                    FontSynthesis.All
+            }
+        )
+
+        val fontFamily = FontTestData.FONT_100_REGULAR.toFontFamily()
+
+        val typeface = resolveAsTypeface(
+            fontFamily = fontFamily,
+            fontWeight = FontWeight.Bold,
+            fontStyle = FontStyle.Italic,
+            fontSynthesis = FontSynthesis.None
+        )
+
+        assertThat(typeface).hasWeightAndStyle(FontWeight.Bold, FontStyle.Italic)
+    }
+
+    @Test
+    fun platformResolveInterceptor_affectsTheResolvedFontFamily() {
+        initializeSubject(
+            platformResolveInterceptor = object : PlatformResolveInterceptor {
+                override fun interceptFontFamily(fontFamily: FontFamily?) =
+                    FontTestData.FONT_100_REGULAR.toFontFamily()
+            }
+        )
+
+        val typeface = resolveAsTypeface(fontFamily = FontFamily.Cursive)
+
+        assertThat(typeface).hasWeightAndStyle(FontWeight.W100, FontStyle.Normal)
+    }
+
+    @Test
+    fun androidResolveInterceptor_affectsAsyncFontResolution_withFallback() {
+        initializeSubject(AndroidFontResolveInterceptor(accessibilityFontWeightAdjustment))
+
+        val loader = AsyncTestTypefaceLoader()
+        val asyncFauxFontW400 = AsyncFauxFont(loader, FontWeight.W400)
+        val asyncFauxFontW700 = AsyncFauxFont(loader, FontWeight.W700)
+        val blockingFauxFontW400 = BlockingFauxFont(loader, Typeface.DEFAULT, FontWeight.W400)
+
+        val fontFamily = FontFamily(
+            asyncFauxFontW400,
+            blockingFauxFontW400,
+            asyncFauxFontW700
+        )
+
+        val fallbackTypeface = resolveAsTypeface(fontFamily, FontWeight.W400)
+        assertThat(fallbackTypeface).hasWeightAndStyle(FontWeight.W700, FontStyle.Normal)
+
+        // loads the W700 async font which should be the matched font
+        loader.completeOne(asyncFauxFontW700, Typeface.MONOSPACE)
+
+        val typeface = resolveAsTypeface(fontFamily, FontWeight.W400)
+        assertThat(typeface).isSameInstanceAs(Typeface.MONOSPACE)
+    }
+
+    @Test
+    fun androidResolveInterceptor_affectsAsyncFontResolution_withBlockingFont() {
+        initializeSubject(AndroidFontResolveInterceptor(accessibilityFontWeightAdjustment))
+
+        val loader = AsyncTestTypefaceLoader()
+        val asyncFauxFontW400 = AsyncFauxFont(loader, FontWeight.W400)
+        val asyncFauxFontW700 = AsyncFauxFont(loader, FontWeight.W700)
+        val blockingFauxFontW700 = BlockingFauxFont(loader, Typeface.SANS_SERIF, FontWeight.W700)
+
+        val fontFamily = FontFamily(
+            asyncFauxFontW400,
+            asyncFauxFontW700,
+            blockingFauxFontW700
+        )
+
+        val blockingTypeface = resolveAsTypeface(fontFamily, FontWeight.W400)
+        assertThat(blockingTypeface).isSameInstanceAs(Typeface.SANS_SERIF)
+
+        // loads the W700 async font which should be the matched font
+        loader.completeOne(asyncFauxFontW700, Typeface.MONOSPACE)
+
+        val typeface = resolveAsTypeface(fontFamily, FontWeight.W400)
+        assertThat(typeface).isSameInstanceAs(Typeface.MONOSPACE)
+    }
+
+    @Test
+    fun androidResolveInterceptor_choosesOptionalFont_whenWeightMatches() {
+        val loader = AsyncTestTypefaceLoader()
+        val optionalFauxFontW400 = OptionalFauxFont(loader, Typeface.MONOSPACE, FontWeight.W400)
+        val optionalFauxFontW700 = OptionalFauxFont(loader, Typeface.SERIF, FontWeight.W700)
+        val blockingFauxFontW700 = BlockingFauxFont(loader, Typeface.SANS_SERIF, FontWeight.W700)
+
+        initializeSubject()
+
+        val fontFamily = FontFamily(
+            optionalFauxFontW400,
+            optionalFauxFontW700,
+            blockingFauxFontW700
+        )
+
+        val typefaceNoAdjustment = resolveAsTypeface(fontFamily, FontWeight.W400)
+        assertThat(typefaceNoAdjustment).isSameInstanceAs(Typeface.MONOSPACE)
+
+        initializeSubject(AndroidFontResolveInterceptor(accessibilityFontWeightAdjustment))
+
+        val typeface = resolveAsTypeface(fontFamily, FontWeight.W400)
+        assertThat(typeface).isSameInstanceAs(Typeface.SERIF)
+    }
 }
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/font/AndroidFontResolveInterceptor.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/font/AndroidFontResolveInterceptor.android.kt
new file mode 100644
index 0000000..0c91c61
--- /dev/null
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/font/AndroidFontResolveInterceptor.android.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.text.font
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.fonts.FontStyle
+import android.os.Build
+import androidx.compose.ui.unit.Density
+
+/**
+ * Android implementation for [PlatformResolveInterceptor].
+ *
+ * Android system accessibility should be able to override any font metric that
+ * affects how FontFamily is resolved. Font Size preference is handled by [Density.fontScale].
+ * This interceptor currently adjusts the Font Weight for Bold Text feature.
+ */
+internal data class AndroidFontResolveInterceptor(
+    private val fontWeightAdjustment: Int
+) : PlatformResolveInterceptor {
+
+    override fun interceptFontWeight(fontWeight: FontWeight): FontWeight {
+        // do not intercept if fontWeightAdjustment is not set or undefined
+        if (fontWeightAdjustment == 0 ||
+            fontWeightAdjustment == Configuration.FONT_WEIGHT_ADJUSTMENT_UNDEFINED) {
+            return fontWeight
+        }
+
+        val finalFontWeight = (fontWeight.weight + fontWeightAdjustment).coerceIn(
+            FontStyle.FONT_WEIGHT_MIN,
+            FontStyle.FONT_WEIGHT_MAX
+        )
+        return FontWeight(finalFontWeight)
+    }
+}
+
+/**
+ * A helper function to create an interceptor using a context.
+ */
+internal fun AndroidFontResolveInterceptor(context: Context): AndroidFontResolveInterceptor {
+    val fontWeightAdjustment = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+        context.resources.configuration.fontWeightAdjustment
+    } else {
+        0
+    }
+    return AndroidFontResolveInterceptor(fontWeightAdjustment)
+}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.android.kt
index b565fd5..bb37ba3 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.android.kt
@@ -36,7 +36,10 @@
 fun createFontFamilyResolver(
     context: Context
 ): FontFamily.Resolver {
-    return FontFamilyResolverImpl(AndroidFontLoader(context))
+    return FontFamilyResolverImpl(
+        AndroidFontLoader(context),
+        AndroidFontResolveInterceptor(context)
+    )
 }
 
 /**
@@ -69,6 +72,7 @@
 ): FontFamily.Resolver {
     return FontFamilyResolverImpl(
         AndroidFontLoader(context),
+        AndroidFontResolveInterceptor(context),
         GlobalTypefaceRequestCache,
         FontListFontFamilyTypefaceAdapter(
             GlobalAsyncTypefaceCache,
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.kt
index fdc1d67..3fd77b3 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.kt
@@ -26,6 +26,8 @@
 @ExperimentalTextApi
 internal class FontFamilyResolverImpl(
     internal val platformFontLoader: PlatformFontLoader /* exposed for desktop ParagraphBuilder */,
+    private val platformResolveInterceptor: PlatformResolveInterceptor =
+        PlatformResolveInterceptor.Default,
     private val typefaceRequestCache: TypefaceRequestCache = GlobalTypefaceRequestCache,
     private val fontListFontFamilyTypefaceAdapter: FontListFontFamilyTypefaceAdapter =
         FontListFontFamilyTypefaceAdapter(GlobalAsyncTypefaceCache),
@@ -33,7 +35,7 @@
         PlatformFontFamilyTypefaceAdapter()
 ) : FontFamily.Resolver {
     private val createDefaultTypeface: (TypefaceRequest) -> Any = {
-        resolve(null, it.fontWeight, it.fontStyle, it.fontSynthesis).value
+        resolve(it.copy(fontFamily = null)).value
     }
 
     override suspend fun preload(
@@ -46,9 +48,9 @@
 
         val typeRequests = fontFamily.fonts.fastMap {
             TypefaceRequest(
-                fontFamily,
-                it.weight,
-                it.style,
+                platformResolveInterceptor.interceptFontFamily(fontFamily),
+                platformResolveInterceptor.interceptFontWeight(it.weight),
+                platformResolveInterceptor.interceptFontStyle(it.style),
                 FontSynthesis.All,
                 platformFontLoader.cacheKey
             )
@@ -76,21 +78,27 @@
         fontStyle: FontStyle,
         fontSynthesis: FontSynthesis,
     ): State<Any> {
-        val typeRequest = TypefaceRequest(
-            fontFamily,
-            fontWeight,
-            fontStyle,
-            fontSynthesis,
+        return resolve(TypefaceRequest(
+            platformResolveInterceptor.interceptFontFamily(fontFamily),
+            platformResolveInterceptor.interceptFontWeight(fontWeight),
+            platformResolveInterceptor.interceptFontStyle(fontStyle),
+            platformResolveInterceptor.interceptFontSynthesis(fontSynthesis),
             platformFontLoader.cacheKey
-        )
-        val result = typefaceRequestCache.runCached(typeRequest) { onAsyncCompletion ->
+        ))
+    }
+
+    /**
+     * Resolves the final [typefaceRequest] without interceptors.
+     */
+    private fun resolve(typefaceRequest: TypefaceRequest): State<Any> {
+        val result = typefaceRequestCache.runCached(typefaceRequest) { onAsyncCompletion ->
             fontListFontFamilyTypefaceAdapter.resolve(
-                typeRequest,
+                typefaceRequest,
                 platformFontLoader,
                 onAsyncCompletion,
                 createDefaultTypeface
             ) ?: platformFamilyTypefaceAdapter.resolve(
-                typeRequest,
+                typefaceRequest,
                 platformFontLoader,
                 onAsyncCompletion,
                 createDefaultTypeface
@@ -100,6 +108,27 @@
     }
 }
 
+/**
+ * Platform level [FontFamily.Resolver] argument interceptor. This interface is
+ * intended to bridge accessibility constraints on any platform with
+ * Compose through the use of [FontFamilyResolverImpl.resolve].
+ */
+internal interface PlatformResolveInterceptor {
+
+    fun interceptFontFamily(fontFamily: FontFamily?): FontFamily? = fontFamily
+
+    fun interceptFontWeight(fontWeight: FontWeight): FontWeight = fontWeight
+
+    fun interceptFontStyle(fontStyle: FontStyle): FontStyle = fontStyle
+
+    fun interceptFontSynthesis(fontSynthesis: FontSynthesis): FontSynthesis = fontSynthesis
+
+    companion object {
+        // NO-OP default interceptor
+        internal val Default: PlatformResolveInterceptor = object : PlatformResolveInterceptor {}
+    }
+}
+
 internal val GlobalTypefaceRequestCache = TypefaceRequestCache()
 @OptIn(ExperimentalTextApi::class)
 internal val GlobalAsyncTypefaceCache = AsyncTypefaceCache()
diff --git a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.sikio.kt b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.sikio.kt
index a0964d6..5be43e1f 100644
--- a/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.sikio.kt
+++ b/compose/ui/ui-text/src/skikoMain/kotlin/androidx/compose/ui/text/font/FontFamilyResolver.sikio.kt
@@ -59,6 +59,7 @@
 ): FontFamily.Resolver {
     return FontFamilyResolverImpl(
         SkiaFontLoader(),
+        PlatformResolveInterceptor.Default,
         GlobalTypefaceRequestCache,
         FontListFontFamilyTypefaceAdapter(
             GlobalAsyncTypefaceCache,
diff --git a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/font/AndroidFontResolverInterceptorTest.kt b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/font/AndroidFontResolverInterceptorTest.kt
new file mode 100644
index 0000000..3de00a3a
--- /dev/null
+++ b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/font/AndroidFontResolverInterceptorTest.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.text.font
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class AndroidFontResolverInterceptorTest {
+    private lateinit var subject: AndroidFontResolveInterceptor
+
+    private fun createSubject(adjustment: Int) {
+        subject = AndroidFontResolveInterceptor(adjustment)
+    }
+
+    @Test
+    fun fontWeightDoesNotChange_whenBoldTextAccessibilityIsNotEnabled() {
+        val testedWeight = 400
+        val adjustment = 0
+        val expected = 400
+        createSubject(adjustment)
+        assertThat(subject.interceptFontWeight(FontWeight(testedWeight)).weight)
+            .isEqualTo(expected)
+    }
+
+    @Test
+    fun fontWeightIncreases_whenBoldTextAccessibilityIsEnabled() {
+        val testedWeight = 400
+        val adjustment = 300
+        val expected = 700
+        createSubject(adjustment)
+        assertThat(subject.interceptFontWeight(FontWeight(testedWeight)).weight)
+            .isEqualTo(expected)
+    }
+
+    @Test
+    fun fontWeightNeverExceeds1000_whenBoldTextAccessibilityIsEnabled() {
+        val testedWeight = 500
+        val adjustment = 600
+        createSubject(adjustment)
+        assertThat(subject.interceptFontWeight(FontWeight(testedWeight)).weight)
+            .isEqualTo(android.graphics.fonts.FontStyle.FONT_WEIGHT_MAX)
+    }
+
+    @Test
+    fun fontWeightWontBeZero_whenBoldTextAccessibilityIsEnabled() {
+        val testedWeight = 500
+        val adjustment = -600
+        createSubject(adjustment)
+        assertThat(subject.interceptFontWeight(FontWeight(testedWeight)).weight)
+            .isEqualTo(android.graphics.fonts.FontStyle.FONT_WEIGHT_MIN)
+    }
+
+    @Test
+    fun fontWeightWontBeNegative_whenBoldTextAccessibilityIsEnabled() {
+        val testedWeight = 500
+        val adjustment = -500
+        createSubject(adjustment)
+        assertThat(subject.interceptFontWeight(FontWeight(testedWeight)).weight)
+            .isEqualTo(android.graphics.fonts.FontStyle.FONT_WEIGHT_MIN)
+    }
+
+    @Test
+    fun fontWeightWontOverflow_whenBoldTextAccessibilityIsEnabled() {
+        val testedWeight = 500
+        val adjustment = Int.MAX_VALUE
+        createSubject(adjustment)
+        assertThat(subject.interceptFontWeight(FontWeight(testedWeight)).weight)
+            .isEqualTo(testedWeight)
+    }
+
+    @Test
+    fun otherFontArgumentsWontChange_whenBoldTextAccessibilityIsEnabled() {
+        val adjustment = 300
+        createSubject(adjustment)
+        assertThat(subject.interceptFontFamily(FontFamily.SansSerif))
+            .isEqualTo(FontFamily.SansSerif)
+
+        assertThat(subject.interceptFontStyle(FontStyle.Normal))
+            .isEqualTo(FontStyle.Normal)
+
+        assertThat(subject.interceptFontSynthesis(FontSynthesis.Weight))
+            .isEqualTo(FontSynthesis.Weight)
+    }
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
index 3efe4c2..1b9ac43 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
@@ -54,6 +54,7 @@
 import androidx.compose.runtime.collection.mutableVectorOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.referentialEqualityPolicy
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.InternalComposeUiApi
@@ -378,7 +379,20 @@
     @Suppress("DEPRECATION", "OverridingDeprecatedMember")
     override val fontLoader: Font.ResourceLoader = AndroidFontResourceLoader(context)
 
-    override val fontFamilyResolver: FontFamily.Resolver = createFontFamilyResolver(context)
+    // Backed by mutableStateOf so that the local provider recomposes when it changes
+    // FontFamily.Resolver is not guaranteed to be stable or immutable, hence referential check
+    override var fontFamilyResolver: FontFamily.Resolver by mutableStateOf(
+        createFontFamilyResolver(context),
+        referentialEqualityPolicy()
+    )
+        private set
+
+    // keeps track of changes in font weight adjustment to update fontFamilyResolver
+    private var currentFontWeightAdjustment: Int =
+        context.resources.configuration.fontWeightAdjustmentCompat
+
+    private val Configuration.fontWeightAdjustmentCompat: Int
+        get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) fontWeightAdjustment else 0
 
     // Backed by mutableStateOf so that the ambient provider recomposes when it changes
     override var layoutDirection by mutableStateOf(
@@ -1409,6 +1423,10 @@
     override fun onConfigurationChanged(newConfig: Configuration) {
         super.onConfigurationChanged(newConfig)
         density = Density(context)
+        if (newConfig.fontWeightAdjustmentCompat != currentFontWeightAdjustment) {
+            currentFontWeightAdjustment = newConfig.fontWeightAdjustmentCompat
+            fontFamilyResolver = createFontFamilyResolver(context)
+        }
         configurationChangeObserver(newConfig)
     }
 
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
index cd20eeb..0b65a0a 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
@@ -89,6 +89,7 @@
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat
 import androidx.core.view.accessibility.AccessibilityNodeProviderCompat
+import androidx.lifecycle.Lifecycle
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.delay
 import kotlin.math.abs
@@ -333,6 +334,11 @@
     }
 
     private fun createNodeInfo(virtualViewId: Int): AccessibilityNodeInfo? {
+        if (view.viewTreeOwners?.lifecycleOwner?.lifecycle?.currentState ==
+            Lifecycle.State.DESTROYED
+        ) {
+            return null
+        }
         val info: AccessibilityNodeInfoCompat = AccessibilityNodeInfoCompat.obtain()
         val semanticsNodeWithAdjustedBounds = currentSemanticsNodes[virtualViewId]
         if (semanticsNodeWithAdjustedBounds == null) {
diff --git a/core/core-splashscreen/api/1.0.0-beta03.txt b/core/core-splashscreen/api/1.0.0-beta03.txt
new file mode 100644
index 0000000..5208466
--- /dev/null
+++ b/core/core-splashscreen/api/1.0.0-beta03.txt
@@ -0,0 +1,36 @@
+// Signature format: 4.0
+package androidx.core.splashscreen {
+
+  public final class SplashScreen {
+    method public static androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+    method public void setKeepOnScreenCondition(androidx.core.splashscreen.SplashScreen.KeepOnScreenCondition condition);
+    method public void setOnExitAnimationListener(androidx.core.splashscreen.SplashScreen.OnExitAnimationListener listener);
+    field public static final androidx.core.splashscreen.SplashScreen.Companion Companion;
+  }
+
+  public static final class SplashScreen.Companion {
+    method public androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+  }
+
+  public static fun interface SplashScreen.KeepOnScreenCondition {
+    method @MainThread public boolean shouldKeepOnScreen();
+  }
+
+  public static fun interface SplashScreen.OnExitAnimationListener {
+    method @MainThread public void onSplashScreenExit(androidx.core.splashscreen.SplashScreenViewProvider splashScreenViewProvider);
+  }
+
+  public final class SplashScreenViewProvider {
+    method public long getIconAnimationDurationMillis();
+    method public long getIconAnimationStartMillis();
+    method public android.view.View getIconView();
+    method public android.view.View getView();
+    method public void remove();
+    property public final long iconAnimationDurationMillis;
+    property public final long iconAnimationStartMillis;
+    property public final android.view.View iconView;
+    property public final android.view.View view;
+  }
+
+}
+
diff --git a/core/core-splashscreen/api/public_plus_experimental_1.0.0-beta03.txt b/core/core-splashscreen/api/public_plus_experimental_1.0.0-beta03.txt
new file mode 100644
index 0000000..5208466
--- /dev/null
+++ b/core/core-splashscreen/api/public_plus_experimental_1.0.0-beta03.txt
@@ -0,0 +1,36 @@
+// Signature format: 4.0
+package androidx.core.splashscreen {
+
+  public final class SplashScreen {
+    method public static androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+    method public void setKeepOnScreenCondition(androidx.core.splashscreen.SplashScreen.KeepOnScreenCondition condition);
+    method public void setOnExitAnimationListener(androidx.core.splashscreen.SplashScreen.OnExitAnimationListener listener);
+    field public static final androidx.core.splashscreen.SplashScreen.Companion Companion;
+  }
+
+  public static final class SplashScreen.Companion {
+    method public androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+  }
+
+  public static fun interface SplashScreen.KeepOnScreenCondition {
+    method @MainThread public boolean shouldKeepOnScreen();
+  }
+
+  public static fun interface SplashScreen.OnExitAnimationListener {
+    method @MainThread public void onSplashScreenExit(androidx.core.splashscreen.SplashScreenViewProvider splashScreenViewProvider);
+  }
+
+  public final class SplashScreenViewProvider {
+    method public long getIconAnimationDurationMillis();
+    method public long getIconAnimationStartMillis();
+    method public android.view.View getIconView();
+    method public android.view.View getView();
+    method public void remove();
+    property public final long iconAnimationDurationMillis;
+    property public final long iconAnimationStartMillis;
+    property public final android.view.View iconView;
+    property public final android.view.View view;
+  }
+
+}
+
diff --git a/core/core-splashscreen/api/res-1.0.0-beta03.txt b/core/core-splashscreen/api/res-1.0.0-beta03.txt
new file mode 100644
index 0000000..6227062
--- /dev/null
+++ b/core/core-splashscreen/api/res-1.0.0-beta03.txt
@@ -0,0 +1,7 @@
+attr postSplashScreenTheme
+attr windowSplashScreenAnimatedIcon
+attr windowSplashScreenAnimationDuration
+attr windowSplashScreenBackground
+dimen splashscreen_icon_size
+style Theme_SplashScreen
+style Theme_SplashScreen_IconBackground
diff --git a/core/core-splashscreen/api/restricted_1.0.0-beta03.txt b/core/core-splashscreen/api/restricted_1.0.0-beta03.txt
new file mode 100644
index 0000000..5208466
--- /dev/null
+++ b/core/core-splashscreen/api/restricted_1.0.0-beta03.txt
@@ -0,0 +1,36 @@
+// Signature format: 4.0
+package androidx.core.splashscreen {
+
+  public final class SplashScreen {
+    method public static androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+    method public void setKeepOnScreenCondition(androidx.core.splashscreen.SplashScreen.KeepOnScreenCondition condition);
+    method public void setOnExitAnimationListener(androidx.core.splashscreen.SplashScreen.OnExitAnimationListener listener);
+    field public static final androidx.core.splashscreen.SplashScreen.Companion Companion;
+  }
+
+  public static final class SplashScreen.Companion {
+    method public androidx.core.splashscreen.SplashScreen installSplashScreen(android.app.Activity);
+  }
+
+  public static fun interface SplashScreen.KeepOnScreenCondition {
+    method @MainThread public boolean shouldKeepOnScreen();
+  }
+
+  public static fun interface SplashScreen.OnExitAnimationListener {
+    method @MainThread public void onSplashScreenExit(androidx.core.splashscreen.SplashScreenViewProvider splashScreenViewProvider);
+  }
+
+  public final class SplashScreenViewProvider {
+    method public long getIconAnimationDurationMillis();
+    method public long getIconAnimationStartMillis();
+    method public android.view.View getIconView();
+    method public android.view.View getView();
+    method public void remove();
+    property public final long iconAnimationDurationMillis;
+    property public final long iconAnimationStartMillis;
+    property public final android.view.View iconView;
+    property public final android.view.View view;
+  }
+
+}
+
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index da32135..756c071 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -605,4 +605,6 @@
 package=".*" found in source AndroidManifest\.xml: .*/AndroidManifest\.xml\.
 Setting the namespace via a source AndroidManifest\.xml's package attribute is deprecated\.
 Please instead set the namespace \(or testNamespace\) in the module's build\.gradle file, as described here: https://developer\.android\.com/studio/build/configure\-app\-module\#set\-namespace
-This migration can be done automatically using the AGP Upgrade Assistant, please refer to https://developer\.android\.com/studio/build/agp\-upgrade\-assistant for more information\.
\ No newline at end of file
+This migration can be done automatically using the AGP Upgrade Assistant, please refer to https://developer\.android\.com/studio/build/agp\-upgrade\-assistant for more information\.
+# > Task :compose:ui:ui:integration-tests:ui-demos:lintAnalyzeDebug
+Index data read correctly
diff --git a/development/update_studio.sh b/development/update_studio.sh
index 66d8b24..464747e 100755
--- a/development/update_studio.sh
+++ b/development/update_studio.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 # Get versions
-AGP_VERSION=${1:-7.3.0-alpha05}
-STUDIO_VERSION_STRING=${2:-"Android Studio Dolphin (2021.3.1) Canary 5"}
+AGP_VERSION=${1:-7.3.0-alpha07}
+STUDIO_VERSION_STRING=${2:-"Android Studio Dolphin (2021.3.1) Canary 7"}
 STUDIO_IFRAME_LINK=`curl "https://developer.android.com/studio/archive.html" | grep iframe | sed "s/.*src=\"\([a-zA-Z0-9\/\._]*\)\".*/https:\/\/android-dot-devsite-v2-prod.appspot.com\1/g"`
 STUDIO_LINK=`curl -s $STUDIO_IFRAME_LINK | grep -C30 "$STUDIO_VERSION_STRING" | grep Linux | tail -n 1 | sed 's/.*a href="\(.*\).*"/\1/g'`
 STUDIO_VERSION=`echo $STUDIO_LINK | sed "s/.*ide-zips\/\(.*\)\/android-studio-.*/\1/g"`
diff --git a/draganddrop/draganddrop/api/1.0.0-beta02.txt b/draganddrop/draganddrop/api/1.0.0-beta02.txt
new file mode 100644
index 0000000..eb19b25
--- /dev/null
+++ b/draganddrop/draganddrop/api/1.0.0-beta02.txt
@@ -0,0 +1,28 @@
+// Signature format: 4.0
+package androidx.draganddrop {
+
+  public final class DropHelper {
+    method public static void configureView(android.app.Activity, android.view.View, String![], androidx.core.view.OnReceiveContentListener);
+    method public static void configureView(android.app.Activity, android.view.View, String![], androidx.draganddrop.DropHelper.Options, androidx.core.view.OnReceiveContentListener);
+  }
+
+  public static final class DropHelper.Options {
+    method @ColorInt public int getHighlightColor();
+    method public int getHighlightCornerRadiusPx();
+    method public java.util.List<android.widget.EditText!> getInnerEditTexts();
+    method public boolean hasHighlightColor();
+    method public boolean hasHighlightCornerRadiusPx();
+    method public boolean shouldAcceptDragsWithLocalState();
+  }
+
+  public static final class DropHelper.Options.Builder {
+    ctor public DropHelper.Options.Builder();
+    method public androidx.draganddrop.DropHelper.Options.Builder addInnerEditTexts(android.widget.EditText!...);
+    method public androidx.draganddrop.DropHelper.Options build();
+    method public androidx.draganddrop.DropHelper.Options.Builder setAcceptDragsWithLocalState(boolean);
+    method public androidx.draganddrop.DropHelper.Options.Builder setHighlightColor(@ColorInt int);
+    method public androidx.draganddrop.DropHelper.Options.Builder setHighlightCornerRadiusPx(int);
+  }
+
+}
+
diff --git a/draganddrop/draganddrop/api/public_plus_experimental_1.0.0-beta02.txt b/draganddrop/draganddrop/api/public_plus_experimental_1.0.0-beta02.txt
new file mode 100644
index 0000000..eb19b25
--- /dev/null
+++ b/draganddrop/draganddrop/api/public_plus_experimental_1.0.0-beta02.txt
@@ -0,0 +1,28 @@
+// Signature format: 4.0
+package androidx.draganddrop {
+
+  public final class DropHelper {
+    method public static void configureView(android.app.Activity, android.view.View, String![], androidx.core.view.OnReceiveContentListener);
+    method public static void configureView(android.app.Activity, android.view.View, String![], androidx.draganddrop.DropHelper.Options, androidx.core.view.OnReceiveContentListener);
+  }
+
+  public static final class DropHelper.Options {
+    method @ColorInt public int getHighlightColor();
+    method public int getHighlightCornerRadiusPx();
+    method public java.util.List<android.widget.EditText!> getInnerEditTexts();
+    method public boolean hasHighlightColor();
+    method public boolean hasHighlightCornerRadiusPx();
+    method public boolean shouldAcceptDragsWithLocalState();
+  }
+
+  public static final class DropHelper.Options.Builder {
+    ctor public DropHelper.Options.Builder();
+    method public androidx.draganddrop.DropHelper.Options.Builder addInnerEditTexts(android.widget.EditText!...);
+    method public androidx.draganddrop.DropHelper.Options build();
+    method public androidx.draganddrop.DropHelper.Options.Builder setAcceptDragsWithLocalState(boolean);
+    method public androidx.draganddrop.DropHelper.Options.Builder setHighlightColor(@ColorInt int);
+    method public androidx.draganddrop.DropHelper.Options.Builder setHighlightCornerRadiusPx(int);
+  }
+
+}
+
diff --git a/draganddrop/draganddrop/api/res-1.0.0-beta02.txt b/draganddrop/draganddrop/api/res-1.0.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/draganddrop/draganddrop/api/res-1.0.0-beta02.txt
diff --git a/draganddrop/draganddrop/api/restricted_1.0.0-beta02.txt b/draganddrop/draganddrop/api/restricted_1.0.0-beta02.txt
new file mode 100644
index 0000000..eb19b25
--- /dev/null
+++ b/draganddrop/draganddrop/api/restricted_1.0.0-beta02.txt
@@ -0,0 +1,28 @@
+// Signature format: 4.0
+package androidx.draganddrop {
+
+  public final class DropHelper {
+    method public static void configureView(android.app.Activity, android.view.View, String![], androidx.core.view.OnReceiveContentListener);
+    method public static void configureView(android.app.Activity, android.view.View, String![], androidx.draganddrop.DropHelper.Options, androidx.core.view.OnReceiveContentListener);
+  }
+
+  public static final class DropHelper.Options {
+    method @ColorInt public int getHighlightColor();
+    method public int getHighlightCornerRadiusPx();
+    method public java.util.List<android.widget.EditText!> getInnerEditTexts();
+    method public boolean hasHighlightColor();
+    method public boolean hasHighlightCornerRadiusPx();
+    method public boolean shouldAcceptDragsWithLocalState();
+  }
+
+  public static final class DropHelper.Options.Builder {
+    ctor public DropHelper.Options.Builder();
+    method public androidx.draganddrop.DropHelper.Options.Builder addInnerEditTexts(android.widget.EditText!...);
+    method public androidx.draganddrop.DropHelper.Options build();
+    method public androidx.draganddrop.DropHelper.Options.Builder setAcceptDragsWithLocalState(boolean);
+    method public androidx.draganddrop.DropHelper.Options.Builder setHighlightColor(@ColorInt int);
+    method public androidx.draganddrop.DropHelper.Options.Builder setHighlightCornerRadiusPx(int);
+  }
+
+}
+
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index cb23e95..454c520 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -2,13 +2,13 @@
 # -----------------------------------------------------------------------------
 # All of the following should be updated in sync.
 # -----------------------------------------------------------------------------
-androidGradlePlugin = "7.3.0-alpha05"
+androidGradlePlugin = "7.3.0-alpha07"
 # NOTE: When updating the lint version we also need to update the `api` version
 # supported by `IssueRegistry`'s.' For e.g. r.android.com/1331903
-androidLint = "30.3.0-alpha05"
+androidLint = "30.3.0-alpha07"
 # Once you have a chosen version of AGP to upgrade to, go to
 # https://developer.android.com/studio/archive and find the matching version of Studio.
-androidStudio = "2021.3.1.5"
+androidStudio = "2021.3.1.7"
 # -----------------------------------------------------------------------------
 
 androidGradlePluginMin = "7.0.4"
@@ -115,7 +115,7 @@
 kotlinCoroutinesRx3 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-rx3", version.ref = "kotlinCoroutines" }
 kotlinDaemonEmbeddable = { module = "org.jetbrains.kotlin:kotlin-daemon-embeddable", version.ref = "kotlin" }
 kotlinKlibCommonizer = { module = "org.jetbrains.kotlin:kotlin-klib-commonizer", version.ref = "kotlin" }
-kotlinMetadataJvm = { module = "org.jetbrains.kotlinx:kotlinx-metadata-jvm", version = "0.3.0" }
+kotlinMetadataJvm = { module = "org.jetbrains.kotlinx:kotlinx-metadata-jvm", version = "0.4.2" }
 kotlinStdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
 kotlinStdlibCommon = { module = "org.jetbrains.kotlin:kotlin-stdlib-common", version.ref = "kotlin" }
 kotlinStdlibJdk8 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
diff --git a/health/health-data-client/api/current.txt b/health/health-data-client/api/current.txt
index 9017e21..f1fb335 100644
--- a/health/health-data-client/api/current.txt
+++ b/health/health-data-client/api/current.txt
@@ -1,4 +1,12 @@
 // Signature format: 4.0
+package androidx.health.data.client {
+
+  public interface HealthDataClient {
+    method public suspend Object? insertRecords(java.util.List<? extends androidx.health.data.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.data.client.response.InsertRecordsResponse> p);
+  }
+
+}
+
 package androidx.health.data.client.metadata {
 
   public final class DataOrigin {
@@ -161,5 +169,47 @@
     field public static final String POSITIVE = "positive";
   }
 
+  public interface Record {
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    property public abstract androidx.health.data.client.metadata.Metadata metadata;
+  }
+
+  public final class Steps implements androidx.health.data.client.records.Record {
+    ctor public Steps(long count, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public long getCount();
+    method public java.time.Instant getEndTime();
+    method public java.time.ZoneOffset? getEndZoneOffset();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getStartTime();
+    method public java.time.ZoneOffset? getStartZoneOffset();
+    property public final long count;
+    property public java.time.Instant endTime;
+    property public java.time.ZoneOffset? endZoneOffset;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant startTime;
+    property public java.time.ZoneOffset? startZoneOffset;
+  }
+
+  public final class Weight implements androidx.health.data.client.records.Record {
+    ctor public Weight(double weightKg, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getTime();
+    method public double getWeightKg();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant time;
+    property public final double weightKg;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
+}
+
+package androidx.health.data.client.response {
+
+  public final class InsertRecordsResponse {
+    method public java.util.List<java.lang.String> getRecordUidsList();
+    property public final java.util.List<java.lang.String> recordUidsList;
+  }
+
 }
 
diff --git a/health/health-data-client/api/public_plus_experimental_current.txt b/health/health-data-client/api/public_plus_experimental_current.txt
index 9017e21..f1fb335 100644
--- a/health/health-data-client/api/public_plus_experimental_current.txt
+++ b/health/health-data-client/api/public_plus_experimental_current.txt
@@ -1,4 +1,12 @@
 // Signature format: 4.0
+package androidx.health.data.client {
+
+  public interface HealthDataClient {
+    method public suspend Object? insertRecords(java.util.List<? extends androidx.health.data.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.data.client.response.InsertRecordsResponse> p);
+  }
+
+}
+
 package androidx.health.data.client.metadata {
 
   public final class DataOrigin {
@@ -161,5 +169,47 @@
     field public static final String POSITIVE = "positive";
   }
 
+  public interface Record {
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    property public abstract androidx.health.data.client.metadata.Metadata metadata;
+  }
+
+  public final class Steps implements androidx.health.data.client.records.Record {
+    ctor public Steps(long count, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public long getCount();
+    method public java.time.Instant getEndTime();
+    method public java.time.ZoneOffset? getEndZoneOffset();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getStartTime();
+    method public java.time.ZoneOffset? getStartZoneOffset();
+    property public final long count;
+    property public java.time.Instant endTime;
+    property public java.time.ZoneOffset? endZoneOffset;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant startTime;
+    property public java.time.ZoneOffset? startZoneOffset;
+  }
+
+  public final class Weight implements androidx.health.data.client.records.Record {
+    ctor public Weight(double weightKg, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getTime();
+    method public double getWeightKg();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant time;
+    property public final double weightKg;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
+}
+
+package androidx.health.data.client.response {
+
+  public final class InsertRecordsResponse {
+    method public java.util.List<java.lang.String> getRecordUidsList();
+    property public final java.util.List<java.lang.String> recordUidsList;
+  }
+
 }
 
diff --git a/health/health-data-client/api/restricted_current.txt b/health/health-data-client/api/restricted_current.txt
index 9017e21..c7d5405 100644
--- a/health/health-data-client/api/restricted_current.txt
+++ b/health/health-data-client/api/restricted_current.txt
@@ -1,4 +1,12 @@
 // Signature format: 4.0
+package androidx.health.data.client {
+
+  public interface HealthDataClient {
+    method public suspend Object? insertRecords(java.util.List<? extends androidx.health.data.client.records.Record> records, kotlin.coroutines.Continuation<? super androidx.health.data.client.response.InsertRecordsResponse> p);
+  }
+
+}
+
 package androidx.health.data.client.metadata {
 
   public final class DataOrigin {
@@ -155,11 +163,71 @@
     field public static final String STANDING_UP = "standing_up";
   }
 
+  @kotlin.PublishedApi internal interface InstantaneousRecord extends androidx.health.data.client.records.Record {
+    method public java.time.Instant getTime();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public abstract java.time.Instant time;
+    property public abstract java.time.ZoneOffset? zoneOffset;
+  }
+
+  @kotlin.PublishedApi internal interface IntervalRecord extends androidx.health.data.client.records.Record {
+    method public java.time.Instant getEndTime();
+    method public java.time.ZoneOffset? getEndZoneOffset();
+    method public java.time.Instant getStartTime();
+    method public java.time.ZoneOffset? getStartZoneOffset();
+    property public abstract java.time.Instant endTime;
+    property public abstract java.time.ZoneOffset? endZoneOffset;
+    property public abstract java.time.Instant startTime;
+    property public abstract java.time.ZoneOffset? startZoneOffset;
+  }
+
   public final class OvulationTestResults {
     field public static final androidx.health.data.client.records.OvulationTestResults INSTANCE;
     field public static final String NEGATIVE = "negative";
     field public static final String POSITIVE = "positive";
   }
 
+  public interface Record {
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    property public abstract androidx.health.data.client.metadata.Metadata metadata;
+  }
+
+  public final class Steps implements androidx.health.data.client.records.IntervalRecord {
+    ctor public Steps(long count, java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public long getCount();
+    method public java.time.Instant getEndTime();
+    method public java.time.ZoneOffset? getEndZoneOffset();
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getStartTime();
+    method public java.time.ZoneOffset? getStartZoneOffset();
+    property public final long count;
+    property public java.time.Instant endTime;
+    property public java.time.ZoneOffset? endZoneOffset;
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant startTime;
+    property public java.time.ZoneOffset? startZoneOffset;
+  }
+
+  public final class Weight implements androidx.health.data.client.records.InstantaneousRecord {
+    ctor public Weight(double weightKg, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.data.client.metadata.Metadata metadata);
+    method public androidx.health.data.client.metadata.Metadata getMetadata();
+    method public java.time.Instant getTime();
+    method public double getWeightKg();
+    method public java.time.ZoneOffset? getZoneOffset();
+    property public androidx.health.data.client.metadata.Metadata metadata;
+    property public java.time.Instant time;
+    property public final double weightKg;
+    property public java.time.ZoneOffset? zoneOffset;
+  }
+
+}
+
+package androidx.health.data.client.response {
+
+  public final class InsertRecordsResponse {
+    method public java.util.List<java.lang.String> getRecordUidsList();
+    property public final java.util.List<java.lang.String> recordUidsList;
+  }
+
 }
 
diff --git a/health/health-data-client/build.gradle b/health/health-data-client/build.gradle
index 53aa9db..10e505b 100644
--- a/health/health-data-client/build.gradle
+++ b/health/health-data-client/build.gradle
@@ -15,6 +15,7 @@
  */
 
 import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
@@ -38,6 +39,7 @@
     testImplementation(libs.testRunner)
     testImplementation(libs.junit)
     testImplementation(libs.truth)
+    testImplementation(libs.kotlinCoroutinesTest)
     androidTestImplementation(libs.testRules)
     testImplementation(libs.mockitoCore)
     testImplementation(libs.robolectric)
@@ -49,7 +51,7 @@
 
 android {
     defaultConfig {
-	    minSdkVersion 27
+        minSdkVersion 27
     }
     buildFeatures {
         aidl = true
@@ -85,3 +87,10 @@
     inceptionYear = "2021"
     description = "read or write user's health and fitness records."
 }
+
+// Allow usage of Kotlin's @OptIn.
+tasks.withType(KotlinCompile).configureEach {
+    kotlinOptions {
+        freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn"]
+    }
+}
\ No newline at end of file
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/HealthDataClient.kt b/health/health-data-client/src/main/java/androidx/health/data/client/HealthDataClient.kt
index 83de6a7..22c0808 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/HealthDataClient.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/HealthDataClient.kt
@@ -22,8 +22,9 @@
 import androidx.health.data.client.permission.Permission
 import androidx.health.data.client.records.Record
 import androidx.health.data.client.request.ChangesTokenRequest
+import androidx.health.data.client.request.ReadRecordsRequest
 import androidx.health.data.client.response.ChangesResponse
-import androidx.health.data.client.response.InsertRecordResponse
+import androidx.health.data.client.response.InsertRecordsResponse
 import androidx.health.data.client.response.ReadRecordResponse
 import androidx.health.data.client.response.ReadRecordsResponse
 import androidx.health.data.client.time.TimeRangeFilter
@@ -31,7 +32,6 @@
 import kotlin.reflect.KClass
 
 /** Interface to access health and fitness records. */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 interface HealthDataClient {
     /**
      * Returns a set of [Permission] granted by the user to this app, out of the input [permissions]
@@ -51,13 +51,13 @@
      *
      * @param records List of records to insert
      * @return List of unique identifiers in the order of inserted records.
+     *
      * @throws RemoteException For any IPC transportation failures.
      * @throws SecurityException For requests with unpermitted access.
      * @throws IOException For any disk I/O issues.
      * @throws IllegalStateException If service is not available.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    suspend fun insertRecords(records: List<Record>): InsertRecordResponse
+    suspend fun insertRecords(records: List<Record>): InsertRecordsResponse
 
     /**
      * Updates one or more [Record] of given UIDs to newly specified values. Update of multiple
@@ -87,7 +87,7 @@
     suspend fun deleteRecords(
         recordType: KClass<out Record>,
         uidsList: List<String>,
-        clientIdsList: List<String>
+        clientIdsList: List<String>,
     )
 
     /**
@@ -124,159 +124,19 @@
     suspend fun <T : Record> readRecord(recordType: KClass<T>, uid: String): ReadRecordResponse<T>
 
     /**
-     * Reads a set of [Record] points determined by time range and other filters.
+     * Retrieves a collection of [Record]s.
      *
-     * @param recordType Which type of [Record] to read, such as `Steps::class`.
-     * @param timeRangeFilter The [TimeRangeFilter] to read from. If open-ended in any direction,
-     * [limit] must be set.
-     * @param dataOriginFilter List of [DataOrigin] to read from, or empty for no filter.
-     * @param ascendingOrder Whether the [Record] should be returned in ascending or descending
-     * order by time. Default is true.
-     * @param limit Maximum number of [Record] to read. Cannot be set together with [pageSize]. Must
-     * be set if [timeRangeFilter] is open-ended in any direction.
-     * @param pageSize Maximum number of [Record] within one page. If there's more data remaining
-     * (and the next page should be read), the response will contain a [pageToken] to be used in the
-     * subsequent read request. Cannot be set together with [limit].
-     * @param pageToken Continuation token to access the next page, returned in the response to the
-     * previous page read request. [pageSize] must be set together with [pageToken].
-     * @return The list of [Record] data points and optionally a [pageToken] to read the next page.
+     * @param T the type of [Record]
+     * @param request [ReadRecordsRequest] object specifying time range and other filters
+     *
+     * @return a response containing a collection of [Record]s.
      * @throws RemoteException For any IPC transportation failures.
      * @throws SecurityException For requests with unpermitted access.
      * @throws IOException For any disk I/O issues.
-     * @throws IllegalStateException For incorrectly set parameters.
      * @throws IllegalStateException If service is not available.
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY)
-    suspend fun <T : Record> readRecords(
-        recordType: KClass<T>,
-        timeRangeFilter: TimeRangeFilter,
-        dataOriginFilter: List<DataOrigin>,
-        ascendingOrder: Boolean,
-        limit: Int?,
-        pageSize: Int?,
-        pageToken: String?
-    ): ReadRecordsResponse<T>
-
-    /** See [HealthDataClient.readRecords]. */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    suspend fun <T : Record> readRecords(
-        recordType: KClass<T>,
-        timeRangeFilter: TimeRangeFilter,
-        ascendingOrder: Boolean,
-        limit: Int
-    ): ReadRecordsResponse<T> =
-        readRecords(
-            recordType = recordType,
-            timeRangeFilter = timeRangeFilter,
-            dataOriginFilter = emptyList(),
-            ascendingOrder = ascendingOrder,
-            limit = limit,
-            pageSize = null,
-            pageToken = null
-        )
-
-    /** See [HealthDataClient.readRecords]. */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    suspend fun <T : Record> readRecords(
-        recordType: KClass<T>,
-        timeRangeFilter: TimeRangeFilter,
-        limit: Int
-    ): ReadRecordsResponse<T> =
-        readRecords(
-            recordType = recordType,
-            timeRangeFilter = timeRangeFilter,
-            dataOriginFilter = emptyList(),
-            ascendingOrder = true,
-            limit = limit,
-            pageSize = null,
-            pageToken = null
-        )
-
-    /** See [HealthDataClient.readRecords]. */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    suspend fun <T : Record> readRecords(
-        recordType: KClass<T>,
-        timeRangeFilter: TimeRangeFilter,
-        ascendingOrder: Boolean,
-        pageSize: Int,
-        pageToken: String?
-    ): ReadRecordsResponse<T> =
-        readRecords(
-            recordType = recordType,
-            timeRangeFilter = timeRangeFilter,
-            dataOriginFilter = emptyList(),
-            ascendingOrder = ascendingOrder,
-            limit = null,
-            pageSize = pageSize,
-            pageToken = pageToken
-        )
-
-    /** See [HealthDataClient.readRecords]. */
-    suspend fun <T : Record> readRecords(
-        recordType: KClass<T>,
-        timeRangeFilter: TimeRangeFilter,
-        pageSize: Int,
-        pageToken: String?
-    ): ReadRecordsResponse<T> =
-        readRecords(
-            recordType = recordType,
-            timeRangeFilter = timeRangeFilter,
-            dataOriginFilter = emptyList(),
-            ascendingOrder = true,
-            limit = null,
-            pageSize = pageSize,
-            pageToken = pageToken
-        )
-
-    /** See [HealthDataClient.readRecords]. */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    suspend fun <T : Record> readRecords(
-        recordType: KClass<T>,
-        timeRangeFilter: TimeRangeFilter,
-        ascendingOrder: Boolean,
-    ): ReadRecordsResponse<T> =
-        readRecords(
-            recordType = recordType,
-            timeRangeFilter = timeRangeFilter,
-            dataOriginFilter = emptyList(),
-            ascendingOrder = ascendingOrder,
-            limit = null,
-            pageSize = null,
-            pageToken = null
-        )
-
-    /** See [HealthDataClient.readRecords]. */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    suspend fun <T : Record> readRecords(
-        recordType: KClass<T>,
-        timeRangeFilter: TimeRangeFilter,
-    ): ReadRecordsResponse<T> =
-        readRecords(
-            recordType = recordType,
-            timeRangeFilter = timeRangeFilter,
-            dataOriginFilter = emptyList(),
-            ascendingOrder = true,
-            limit = null,
-            pageSize = null,
-            pageToken = null
-        )
-
-    /** See [HealthDataClient.readRecords]. */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    suspend fun <T : Record> readRecords(
-        recordType: KClass<T>,
-        timeRangeFilter: TimeRangeFilter,
-        dataOriginFilter: List<DataOrigin>,
-    ): ReadRecordsResponse<T> =
-        readRecords(
-            recordType = recordType,
-            timeRangeFilter = timeRangeFilter,
-            dataOriginFilter = dataOriginFilter,
-            ascendingOrder = true,
-            limit = null,
-            pageSize = null,
-            pageToken = null
-        )
+    suspend fun <T : Record> readRecords(request: ReadRecordsRequest<T>): ReadRecordsResponse<T>
 
     /**
      * Reads [AggregateMetric]s according to requested read criteria: [Record]s from
@@ -298,14 +158,14 @@
     suspend fun aggregate(
         aggregateMetrics: Set<AggregateMetric>,
         timeRangeFilter: TimeRangeFilter,
-        dataOriginFilter: List<DataOrigin>
+        dataOriginFilter: List<DataOrigin>,
     ): AggregateDataRow
 
     // TODO(b/219327548): Adds overload with groupBy that return a list
 
     /**
-     * Retrieves a changes-token, representing current point in time in the underlying Android
-     * Health Platform for a given [ChangesTokenRequest]. Changes-tokens are used in [getChanges] to
+     * Retrieves a changes-token, representing a point in time in the underlying Android Health
+     * Platform for a given [ChangesTokenRequest]. Changes-tokens are used in [getChanges] to
      * retrieve changes since that point in time.
      *
      * Changes-tokens represent a point in time after which the client is interested in knowing the
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/HealthDataService.kt b/health/health-data-client/src/main/java/androidx/health/data/client/HealthDataService.kt
index 7da103c..4957a40 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/HealthDataService.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/HealthDataService.kt
@@ -22,6 +22,7 @@
 import androidx.annotation.RestrictTo
 import androidx.health.data.client.impl.HealthDataClientImpl
 import androidx.health.platform.client.HealthDataService
+import java.lang.IllegalStateException
 
 /**
  * Entry point for connecting to Health Data Provider on the device and creating instances of
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/HealthDataClientImpl.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/HealthDataClientImpl.kt
index ac6dacc..02064b0 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/HealthDataClientImpl.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/impl/HealthDataClientImpl.kt
@@ -34,8 +34,9 @@
 import androidx.health.data.client.permission.Permission
 import androidx.health.data.client.records.Record
 import androidx.health.data.client.request.ChangesTokenRequest
+import androidx.health.data.client.request.ReadRecordsRequest
 import androidx.health.data.client.response.ChangesResponse
-import androidx.health.data.client.response.InsertRecordResponse
+import androidx.health.data.client.response.InsertRecordsResponse
 import androidx.health.data.client.response.ReadRecordResponse
 import androidx.health.data.client.response.ReadRecordsResponse
 import androidx.health.data.client.time.TimeRangeFilter
@@ -61,9 +62,9 @@
             .toSet()
     }
 
-    override suspend fun insertRecords(records: List<Record>): InsertRecordResponse {
+    override suspend fun insertRecords(records: List<Record>): InsertRecordsResponse {
         val uidList = delegate.insertData(records.map { it.toProto() }).await()
-        return InsertRecordResponse(recordUidsList = uidList)
+        return InsertRecordsResponse(recordUidsList = uidList)
     }
 
     override suspend fun updateRecords(records: List<Record>) {
@@ -135,28 +136,9 @@
     }
 
     override suspend fun <T : Record> readRecords(
-        recordType: KClass<T>,
-        timeRangeFilter: TimeRangeFilter,
-        dataOriginFilter: List<DataOrigin>,
-        ascendingOrder: Boolean,
-        limit: Int?,
-        pageSize: Int?,
-        pageToken: String?
+        request: ReadRecordsRequest<T>
     ): ReadRecordsResponse<T> {
-        val proto =
-            delegate
-                .readDataRange(
-                    toReadDataRangeRequestProto(
-                        recordType,
-                        timeRangeFilter,
-                        dataOriginFilter,
-                        ascendingOrder,
-                        limit,
-                        pageSize,
-                        pageToken
-                    )
-                )
-                .await()
+        val proto = delegate.readDataRange(toReadDataRangeRequestProto(request)).await()
         return toReadRecordsResponse(proto)
     }
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/RecordsTypeNameMap.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/RecordsTypeNameMap.kt
index 6806397..23587ba 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/RecordsTypeNameMap.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/datatype/RecordsTypeNameMap.kt
@@ -49,7 +49,6 @@
 import androidx.health.data.client.records.Nutrition
 import androidx.health.data.client.records.OvulationTest
 import androidx.health.data.client.records.OxygenSaturation
-import androidx.health.data.client.records.Pace
 import androidx.health.data.client.records.Power
 import androidx.health.data.client.records.Repetitions
 import androidx.health.data.client.records.RespiratoryRate
@@ -65,6 +64,7 @@
 import androidx.health.data.client.records.Vo2Max
 import androidx.health.data.client.records.WaistCircumference
 import androidx.health.data.client.records.Weight
+import androidx.health.data.client.records.WheelchairPushes
 
 private val ALL_RECORDS_TYPES =
     setOf(
@@ -102,7 +102,6 @@
         Nutrition::class,
         OvulationTest::class,
         OxygenSaturation::class,
-        Pace::class,
         Power::class,
         Repetitions::class,
         RespiratoryRate::class,
@@ -117,6 +116,7 @@
         TotalEnergyBurned::class,
         Vo2Max::class,
         WaistCircumference::class,
+        WheelchairPushes::class,
         Weight::class,
     )
 
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordConverters.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordConverters.kt
index 43c5a18..b90a1ef 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordConverters.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/ProtoToRecordConverters.kt
@@ -49,7 +49,6 @@
 import androidx.health.data.client.records.Nutrition
 import androidx.health.data.client.records.OvulationTest
 import androidx.health.data.client.records.OxygenSaturation
-import androidx.health.data.client.records.Pace
 import androidx.health.data.client.records.Power
 import androidx.health.data.client.records.Record
 import androidx.health.data.client.records.Repetitions
@@ -66,6 +65,7 @@
 import androidx.health.data.client.records.Vo2Max
 import androidx.health.data.client.records.WaistCircumference
 import androidx.health.data.client.records.Weight
+import androidx.health.data.client.records.WheelchairPushes
 import androidx.health.platform.client.proto.DataProto
 import java.lang.RuntimeException
 
@@ -258,13 +258,6 @@
                     zoneOffset = zoneOffset,
                     metadata = metadata
                 )
-            "Pace" ->
-                Pace(
-                    pace = getDouble("pace"),
-                    time = time,
-                    zoneOffset = zoneOffset,
-                    metadata = metadata
-                )
             "Power" ->
                 Power(
                     power = getDouble("power"),
@@ -510,6 +503,15 @@
                     endZoneOffset = endZoneOffset,
                     metadata = metadata
                 )
+            "WheelchairPushes" ->
+                WheelchairPushes(
+                    count = getLong("count"),
+                    startTime = startTime,
+                    startZoneOffset = startZoneOffset,
+                    endTime = endTime,
+                    endZoneOffset = endZoneOffset,
+                    metadata = metadata
+                )
             else -> throw RuntimeException("Unknown data type ${dataType.name}")
         }
     }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoConverters.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoConverters.kt
index 1f174d5..a8e1b6f 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoConverters.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/records/RecordToProtoConverters.kt
@@ -49,7 +49,6 @@
 import androidx.health.data.client.records.Nutrition
 import androidx.health.data.client.records.OvulationTest
 import androidx.health.data.client.records.OxygenSaturation
-import androidx.health.data.client.records.Pace
 import androidx.health.data.client.records.Power
 import androidx.health.data.client.records.Record
 import androidx.health.data.client.records.Repetitions
@@ -66,6 +65,7 @@
 import androidx.health.data.client.records.Vo2Max
 import androidx.health.data.client.records.WaistCircumference
 import androidx.health.data.client.records.Weight
+import androidx.health.data.client.records.WheelchairPushes
 import androidx.health.platform.client.proto.DataProto
 import java.lang.RuntimeException
 
@@ -218,11 +218,6 @@
                 .setDataType(protoDataType("OxygenSaturation"))
                 .apply { putValues("percentage", doubleVal(percentage)) }
                 .build()
-        is Pace ->
-            instantaneousProto()
-                .setDataType(protoDataType("Pace"))
-                .apply { putValues("pace", doubleVal(pace)) }
-                .build()
         is Power ->
             instantaneousProto()
                 .setDataType(protoDataType("Power"))
@@ -490,6 +485,11 @@
                 .setDataType(protoDataType("TotalEnergyBurned"))
                 .apply { putValues("energy", doubleVal(energy)) }
                 .build()
+        is WheelchairPushes ->
+            intervalProto()
+                .setDataType(protoDataType("WheelchairPushes"))
+                .apply { putValues("count", longVal(count)) }
+                .build()
         else -> throw RuntimeException("Unsupported yet!")
     }
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/ReadDataRangeRequestToProto.kt b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/ReadDataRangeRequestToProto.kt
index 0d51701..fa38d639 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/ReadDataRangeRequestToProto.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/impl/converters/request/ReadDataRangeRequestToProto.kt
@@ -19,34 +19,33 @@
 import androidx.health.data.client.impl.converters.time.toProto
 import androidx.health.data.client.metadata.DataOrigin
 import androidx.health.data.client.records.Record
-import androidx.health.data.client.time.TimeRangeFilter
+import androidx.health.data.client.request.ReadRecordsRequest
 import androidx.health.platform.client.proto.DataProto
 import androidx.health.platform.client.proto.RequestProto
-import kotlin.reflect.KClass
 
 /** Converts public API object into internal proto for ipc. */
-fun toReadDataRangeRequestProto(
-    dataTypeKC: KClass<out Record>,
-    timeRangeFilter: TimeRangeFilter,
-    dataOriginFilter: List<DataOrigin>,
-    ascOrdering: Boolean?,
-    limit: Int?,
-    pageSize: Int?,
-    pageToken: String?
+fun <T : Record> toReadDataRangeRequestProto(
+    request: ReadRecordsRequest<T>
 ): RequestProto.ReadDataRangeRequest {
     return RequestProto.ReadDataRangeRequest.newBuilder()
-        .setDataType(DataProto.DataType.newBuilder().setName(dataTypeKC.toDataTypeName()).build())
+        .setDataType(
+            DataProto.DataType.newBuilder().setName(request.recordType.toDataTypeName()).build()
+        )
         .apply {
-            setTimeSpec(timeRangeFilter.toProto())
+            setTimeSpec(request.timeRangeFilter.toProto())
             addAllDataOriginFilters(
-                dataOriginFilter.map {
+                request.dataOriginFilter.map {
                     DataProto.DataOrigin.newBuilder().setApplicationId(it.packageName).build()
                 }
             )
-            ascOrdering?.let { setAscOrdering(ascOrdering) }
-            limit?.let { setLimit(limit) }
-            pageSize?.let { setPageSize(pageSize) }
-            pageToken?.let { setPageToken(pageToken) }
+            setAscOrdering(request.ascendingOrder)
+            if (request.hasLimit()) {
+                setLimit(request.limit)
+            }
+            if (request.hasPageSize()) {
+                setPageSize(request.pageSize)
+            }
+            request.pageToken?.let { setPageToken(it) }
         }
         .build()
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/permission/HealthDataRequestPermissions.kt b/health/health-data-client/src/main/java/androidx/health/data/client/permission/HealthDataRequestPermissions.kt
index 7f8b825..28fbe6b 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/permission/HealthDataRequestPermissions.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/permission/HealthDataRequestPermissions.kt
@@ -23,7 +23,6 @@
 import androidx.health.data.client.impl.converters.permission.toJetpackPermission
 import androidx.health.data.client.impl.converters.permission.toProtoPermission
 import androidx.health.platform.client.permission.Permission as ProtoPermission
-import androidx.health.platform.client.service.HealthDataServiceConstants
 import androidx.health.platform.client.service.HealthDataServiceConstants.ACTION_REQUEST_PERMISSIONS
 import androidx.health.platform.client.service.HealthDataServiceConstants.KEY_GRANTED_PERMISSIONS_JETPACK
 import androidx.health.platform.client.service.HealthDataServiceConstants.KEY_REQUESTED_PERMISSIONS_JETPACK
@@ -44,7 +43,6 @@
                 .toCollection(ArrayList())
         return Intent(ACTION_REQUEST_PERMISSIONS).apply {
             putParcelableArrayListExtra(KEY_REQUESTED_PERMISSIONS_JETPACK, protoPermissionList)
-            putExtra(HealthDataServiceConstants.KEY_PACKAGE_NAME, context.packageName)
             if (providerPackageName.isNotEmpty()) {
                 setPackage(providerPackageName)
             }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityTypes.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityTypes.kt
index 805d7be..c51ac08 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityTypes.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/ActivityTypes.kt
@@ -101,8 +101,7 @@
     const val WALKING = "walking"
     const val WATER_POLO = "water_polo"
     const val WEIGHTLIFTING = "weightlifting"
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    const val WHEELCHAIR = "wheelchair"
+    @RestrictTo(RestrictTo.Scope.LIBRARY) const val WHEELCHAIR = "wheelchair"
     const val WORKOUT = "workout"
     const val YOGA = "yoga"
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/InstantaneousRecord.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/InstantaneousRecord.kt
index 362eeb7..ef549f0 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/InstantaneousRecord.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/InstantaneousRecord.kt
@@ -15,17 +15,21 @@
  */
 package androidx.health.data.client.records
 
-import androidx.annotation.RestrictTo
 import java.time.Instant
 import java.time.ZoneOffset
 
-/** Common interface that records happenned at an instantaneous time inherits. */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-interface InstantaneousRecord : Record {
-    val time: Instant
+/**
+ * A record that contains an instantaneous measurement.
+ *
+ * @see IntervalRecord for records with measurement of a time interval.
+ */
+@PublishedApi
+internal interface InstantaneousRecord : Record {
+    /** Time the record happened. */
+    public val time: Instant
     /**
-     * User experienced zoneoffset at [time], or null if unknown. Providing these will help history
+     * User experienced zone offset at [time], or null if unknown. Providing these will help history
      * aggregations results stay consistent should user travel.
      */
-    val zoneOffset: ZoneOffset?
+    public val zoneOffset: ZoneOffset?
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/IntervalRecord.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/IntervalRecord.kt
index 06f10a4..7ead665 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/IntervalRecord.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/IntervalRecord.kt
@@ -15,23 +15,28 @@
  */
 package androidx.health.data.client.records
 
-import androidx.annotation.RestrictTo
 import java.time.Instant
 import java.time.ZoneOffset
 
-/** Common interface that records with time interval inherits. */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-interface IntervalRecord : Record {
-    val startTime: Instant
-    val endTime: Instant
+/**
+ * A record that contains a measurement with a time interval.
+ *
+ * @see InstantaneousRecord for records with instantaneous measurement.
+ */
+@PublishedApi
+internal interface IntervalRecord : Record {
+    /** Start time of the record. */
+    public val startTime: Instant
+    /** End time of the record. */
+    public val endTime: Instant
     /**
-     * User experienced zoneoffset at [startTime], or null if unknown. Providing these will help
+     * User experienced zone offset at [startTime], or null if unknown. Providing these will help
      * history aggregations results stay consistent should user travel.
      */
-    val startZoneOffset: ZoneOffset?
+    public val startZoneOffset: ZoneOffset?
     /**
-     * User experienced zoneoffset at [endTime], or null if unknown. Providing these will help
+     * User experienced zone offset at [endTime], or null if unknown. Providing these will help
      * history aggregations results stay consistent should user travel.
      */
-    val endZoneOffset: ZoneOffset?
+    public val endZoneOffset: ZoneOffset?
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Record.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/Record.kt
index 83d89ae..ba8099d 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Record.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/Record.kt
@@ -15,11 +15,10 @@
  */
 package androidx.health.data.client.records
 
-import androidx.annotation.RestrictTo
 import androidx.health.data.client.metadata.Metadata
 
 /** Common interface shared by readable or writable records. */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-interface Record {
-    val metadata: Metadata
+public interface Record {
+    /** Set of common metadata associated with the written record. */
+    public val metadata: Metadata
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Steps.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/Steps.kt
index a3ad847..18376eb 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Steps.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/Steps.kt
@@ -15,7 +15,6 @@
  */
 package androidx.health.data.client.records
 
-import androidx.annotation.RestrictTo
 import androidx.health.data.client.aggregate.LongAggregateMetric
 import androidx.health.data.client.metadata.Metadata
 import java.time.Instant
@@ -30,7 +29,6 @@
  * of the values together for a period of time calculates the total number of steps during that
  * period.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 public class Steps(
     /** Count. Required field. Valid range: 1-1000000. */
     public val count: Long,
@@ -64,9 +62,10 @@
         return result
     }
 
-    companion object {
+    internal companion object {
         /** Metric identifier to retrieve total steps count from [AggregateDataRow]. */
         @JvmStatic
-        val STEPS_COUNT_TOTAL: LongAggregateMetric = LongAggregateMetric("Steps", "total", "count")
+        internal val STEPS_COUNT_TOTAL: LongAggregateMetric =
+            LongAggregateMetric("Steps", "total", "count")
     }
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/Weight.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/Weight.kt
index d8b5445..244fb36 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/records/Weight.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/Weight.kt
@@ -15,14 +15,12 @@
  */
 package androidx.health.data.client.records
 
-import androidx.annotation.RestrictTo
 import androidx.health.data.client.aggregate.DoubleAggregateMetric
 import androidx.health.data.client.metadata.Metadata
 import java.time.Instant
 import java.time.ZoneOffset
 
 /** Captures that user's weight in kilograms. */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 public class Weight(
     /** User's weight in kilograms. Required field. Valid range: 0-1000. */
     public val weightKg: Double,
@@ -51,17 +49,20 @@
         return result
     }
 
-    companion object {
+    internal companion object {
         /** Metric identifier to retrieve average weight from [AggregateDataRow]. */
         @JvmStatic
-        val WEIGHT_AVG: DoubleAggregateMetric = DoubleAggregateMetric("Weight", "avg", "weight")
+        internal val WEIGHT_AVG: DoubleAggregateMetric =
+            DoubleAggregateMetric("Weight", "avg", "weight")
 
         /** Metric identifier to retrieve minimum weight from [AggregateDataRow]. */
         @JvmStatic
-        val WEIGHT_MIN: DoubleAggregateMetric = DoubleAggregateMetric("Weight", "min", "weight")
+        internal val WEIGHT_MIN: DoubleAggregateMetric =
+            DoubleAggregateMetric("Weight", "min", "weight")
 
         /** Metric identifier to retrieve maximum weight from [AggregateDataRow]. */
         @JvmStatic
-        val WEIGHT_MAX: DoubleAggregateMetric = DoubleAggregateMetric("Weight", "max", "weight")
+        internal val WEIGHT_MAX: DoubleAggregateMetric =
+            DoubleAggregateMetric("Weight", "max", "weight")
     }
 }
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/records/WheelchairPushes.kt b/health/health-data-client/src/main/java/androidx/health/data/client/records/WheelchairPushes.kt
new file mode 100644
index 0000000..d655ffc
--- /dev/null
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/records/WheelchairPushes.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.health.data.client.records
+
+import androidx.annotation.RestrictTo
+import androidx.health.data.client.metadata.Metadata
+import java.time.Instant
+import java.time.ZoneOffset
+
+/**
+ * Captures the number of wheelchair pushes done since the last reading. Each push is only reported
+ * once so data points shouldn't have overlapping time. The start time of each data point should
+ * represent the start of the interval in which pushes were made.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class WheelchairPushes(
+    /** Count. Required field. Valid range: 1-1000000. */
+    public val count: Long,
+    override val startTime: Instant,
+    override val startZoneOffset: ZoneOffset?,
+    override val endTime: Instant,
+    override val endZoneOffset: ZoneOffset?,
+    override val metadata: Metadata = Metadata.EMPTY,
+) : IntervalRecord {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is WheelchairPushes) return false
+
+        if (count != other.count) return false
+        if (startTime != other.startTime) return false
+        if (startZoneOffset != other.startZoneOffset) return false
+        if (endTime != other.endTime) return false
+        if (endZoneOffset != other.endZoneOffset) return false
+        if (metadata != other.metadata) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = 0
+        result = 31 * result + count.hashCode()
+        result = 31 * result + (startZoneOffset?.hashCode() ?: 0)
+        result = 31 * result + endTime.hashCode()
+        result = 31 * result + (endZoneOffset?.hashCode() ?: 0)
+        result = 31 * result + metadata.hashCode()
+        return result
+    }
+}
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/request/ReadRecordsRequest.kt b/health/health-data-client/src/main/java/androidx/health/data/client/request/ReadRecordsRequest.kt
new file mode 100644
index 0000000..93d6b51
--- /dev/null
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/request/ReadRecordsRequest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.health.data.client.request
+
+import androidx.annotation.RestrictTo
+import androidx.health.data.client.metadata.DataOrigin
+import androidx.health.data.client.records.Record
+import androidx.health.data.client.time.TimeRangeFilter
+import kotlin.reflect.KClass
+
+/**
+ * Request object to read [Record]s in Android Health Platform determined by time range and other
+ * filters.
+ *
+ * @property recordType Which type of [Record] to read, such as `Steps::class`.
+ * @property timeRangeFilter The [TimeRangeFilter] to read from. If open-ended in any direction,
+ * [limit] or [pageSize] must be set.
+ * @property dataOriginFilter List of [DataOrigin] to read from, or empty for no filter.
+ * @property ascendingOrder Whether the [Record] should be returned in ascending or descending order
+ * by time. Default is true.
+ * @property limit Maximum number of [Record] to read. Cannot be set together with [pageSize]. Must
+ * be set if [timeRangeFilter] is open-ended in any direction.
+ * @property pageSize Maximum number of [Record] within one page. If there's more data remaining
+ * (and the next page should be read), the response will contain a [pageToken] to be used in the
+ * subsequent read request. Cannot be set together with [limit].
+ * @property pageToken Continuation token to access the next page, returned in the response to the
+ * previous page read request. [pageSize] must be set together with [pageToken].
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class ReadRecordsRequest<T : Record>(
+    val recordType: KClass<T>,
+    val timeRangeFilter: TimeRangeFilter,
+    val dataOriginFilter: List<DataOrigin> = emptyList(),
+    val ascendingOrder: Boolean = true,
+    val limit: Int = 0,
+    val pageSize: Int = 0,
+    val pageToken: String? = null
+) {
+    init {
+        require(limit == 0 || pageSize == 0) { "pageSize and limit can't be used at the same time" }
+        if (timeRangeFilter.isOpenEnded()) {
+            require(limit > 0 || pageSize > 0) {
+                "When timeRangeFilter is open-ended, either limit or pageSize must be set"
+            }
+        }
+        if (pageToken != null) {
+            require(pageSize > 0) { "pageToken must be set with pageSize" }
+        }
+    }
+
+    internal fun hasLimit(): Boolean = limit > 0
+
+    internal fun hasPageSize(): Boolean = pageSize > 0
+}
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/response/InsertRecordResponse.kt b/health/health-data-client/src/main/java/androidx/health/data/client/response/InsertRecordsResponse.kt
similarity index 90%
rename from health/health-data-client/src/main/java/androidx/health/data/client/response/InsertRecordResponse.kt
rename to health/health-data-client/src/main/java/androidx/health/data/client/response/InsertRecordsResponse.kt
index 8c1ca9a..3806ef6 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/response/InsertRecordResponse.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/response/InsertRecordsResponse.kt
@@ -15,15 +15,12 @@
  */
 package androidx.health.data.client.response
 
-import androidx.annotation.RestrictTo
-
 /**
  * Response to record insertion.
  *
  * @see [HealthDataClient.insertRecord]
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-class InsertRecordResponse
+public class InsertRecordsResponse
 internal constructor(
     /*
      * Contains
diff --git a/health/health-data-client/src/main/java/androidx/health/data/client/time/TimeRangeFilter.kt b/health/health-data-client/src/main/java/androidx/health/data/client/time/TimeRangeFilter.kt
index a72c7a2..b1f261c 100644
--- a/health/health-data-client/src/main/java/androidx/health/data/client/time/TimeRangeFilter.kt
+++ b/health/health-data-client/src/main/java/androidx/health/data/client/time/TimeRangeFilter.kt
@@ -87,4 +87,7 @@
                 localEndTime = null
             )
     }
+
+    internal fun isOpenEnded(): Boolean =
+        (localStartTime == null || localEndTime == null) && (startTime == null || endTime == null)
 }
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/HealthDataServiceTest.kt b/health/health-data-client/src/test/java/androidx/health/data/client/HealthDataServiceTest.kt
new file mode 100644
index 0000000..e08b604
--- /dev/null
+++ b/health/health-data-client/src/test/java/androidx/health/data/client/HealthDataServiceTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.health.data.client
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageInfo
+import android.os.Build
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import java.lang.IllegalStateException
+import java.lang.UnsupportedOperationException
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.Shadows
+import org.robolectric.annotation.Config
+
+private const val PROVIDER_PACKAGE_NAME = "com.example.fake.provider"
+
+@RunWith(AndroidJUnit4::class)
+class HealthDataServiceTest {
+
+    private lateinit var context: Context
+
+    @Before
+    fun setUp() {
+        context = ApplicationProvider.getApplicationContext()
+    }
+
+    @Test
+    fun noBackingImplementation_unavailable() {
+        val packageManager = context.packageManager
+        Shadows.shadowOf(packageManager).removePackage(PROVIDER_PACKAGE_NAME)
+        assertThat(HealthDataService.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME))).isFalse()
+        assertThrows(IllegalStateException::class.java) {
+            HealthDataService.getClient(context, listOf(PROVIDER_PACKAGE_NAME))
+        }
+    }
+
+    @Test
+    fun backingImplementation_notEnabled_unavailable() {
+        installPackage(context, PROVIDER_PACKAGE_NAME, enabled = false)
+        assertThat(HealthDataService.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME))).isFalse()
+        assertThrows(IllegalStateException::class.java) {
+            HealthDataService.getClient(context, listOf(PROVIDER_PACKAGE_NAME))
+        }
+    }
+
+    @Test
+    fun backingImplementation_enabled_isAvailable() {
+        installPackage(context, PROVIDER_PACKAGE_NAME, enabled = true)
+        assertThat(HealthDataService.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME))).isTrue()
+        HealthDataService.getClient(context, listOf(PROVIDER_PACKAGE_NAME))
+    }
+
+    @Test
+    @Config(sdk = [Build.VERSION_CODES.O_MR1])
+    fun sdkVersionTooOld_unavailable() {
+        assertThat(HealthDataService.isAvailable(context, listOf(PROVIDER_PACKAGE_NAME))).isFalse()
+        assertThrows(UnsupportedOperationException::class.java) {
+            HealthDataService.getClient(context, listOf(PROVIDER_PACKAGE_NAME))
+        }
+    }
+
+    private fun installPackage(context: Context, packageName: String, enabled: Boolean) {
+        val packageInfo = PackageInfo()
+        packageInfo.packageName = packageName
+        packageInfo.applicationInfo = ApplicationInfo()
+        packageInfo.applicationInfo.enabled = enabled
+        val packageManager = context.packageManager
+        Shadows.shadowOf(packageManager).installPackage(packageInfo)
+    }
+}
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/impl/HealthDataClientImplTest.kt b/health/health-data-client/src/test/java/androidx/health/data/client/impl/HealthDataClientImplTest.kt
index 70ba21d..7a9b2ec 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/impl/HealthDataClientImplTest.kt
+++ b/health/health-data-client/src/test/java/androidx/health/data/client/impl/HealthDataClientImplTest.kt
@@ -28,6 +28,7 @@
 import androidx.health.data.client.records.Steps
 import androidx.health.data.client.records.Weight
 import androidx.health.data.client.request.ChangesTokenRequest
+import androidx.health.data.client.request.ReadRecordsRequest
 import androidx.health.data.client.time.TimeRangeFilter
 import androidx.health.platform.client.impl.ServiceBackedHealthDataClient
 import androidx.health.platform.client.impl.error.errorCodeExceptionMap
@@ -39,15 +40,13 @@
 import androidx.test.espresso.intent.Intents
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
-import java.time.Duration
 import java.time.Instant
-import kotlinx.coroutines.CoroutineScope
+import kotlin.test.assertFailsWith
 import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.async
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.runTest
 import org.junit.After
-import org.junit.Assert.assertThrows
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -65,8 +64,10 @@
         { readRecord(Steps::class, "uid") },
         {
             readRecords(
-                Steps::class,
-                TimeRangeFilter.exact(Instant.ofEpochMilli(1234L), Instant.ofEpochMilli(1235L))
+                ReadRecordsRequest(
+                    Steps::class,
+                    TimeRangeFilter.exact(Instant.ofEpochMilli(1234L), Instant.ofEpochMilli(1235L))
+                )
             )
         },
         { getChanges("token") },
@@ -75,8 +76,10 @@
 
 @Suppress("GoodTime") // Safe to use in test setup
 @RunWith(AndroidJUnit4::class)
+@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
 class HealthDataClientImplTest {
-    private lateinit var healthConnectClient: HealthDataClientImpl
+
+    private lateinit var healthDataClient: HealthDataClientImpl
     private lateinit var fakeAhpServiceStub: FakeHealthDataService
 
     @Before
@@ -84,7 +87,7 @@
         val clientConfig =
             ClientConfiguration("FakeAHPProvider", PROVIDER_PACKAGE_NAME, "FakeProvider")
 
-        healthConnectClient =
+        healthDataClient =
             HealthDataClientImpl(
                 ServiceBackedHealthDataClient(
                     ApplicationProvider.getApplicationContext(),
@@ -115,48 +118,43 @@
     }
 
     @Test(timeout = 60000L)
-    fun apiMethods_hasError_throwsException() {
+    fun apiMethods_hasError_throwsException() = runTest {
         for (error in errorCodeExceptionMap) {
             fakeAhpServiceStub.setErrorCode(error.key)
-            val responseList = mutableListOf<Deferred<Unit>>()
+            val responseList = mutableListOf<Deferred<Any>>()
             for (method in API_METHOD_LIST) {
                 responseList.add(
-                    CoroutineScope(Dispatchers.Default).async { healthConnectClient.method() }
+                    async { assertFailsWith(error.value) { healthDataClient.method() } }
                 )
             }
-
-            // wait for the client to enqueue message and handle message
-            Thread.sleep(Duration.ofMillis(1000).toMillis())
-            Shadows.shadowOf(Looper.getMainLooper()).idleFor(Duration.ofMillis(1000))
-
+            advanceUntilIdle()
+            waitForMainLooperIdle()
             for (response in responseList) {
-                assertThrows(error.value.java) { runBlocking { response.await() } }
+                response.await()
             }
         }
     }
 
-    @Test(timeout = 60000L)
-    fun insertRecords_steps() {
-        val deferred =
-            CoroutineScope(Dispatchers.Default).async {
-                healthConnectClient.insertRecords(
-                    listOf(
-                        Steps(
-                            count = 100,
-                            startTime = Instant.ofEpochMilli(1234L),
-                            startZoneOffset = null,
-                            endTime = Instant.ofEpochMilli(5678L),
-                            endZoneOffset = null
-                        )
+    @Test(timeout = 10000L)
+    fun insertRecords_steps() = runTest {
+        val deferred = async {
+            healthDataClient.insertRecords(
+                listOf(
+                    Steps(
+                        count = 100,
+                        startTime = Instant.ofEpochMilli(1234L),
+                        startZoneOffset = null,
+                        endTime = Instant.ofEpochMilli(5678L),
+                        endZoneOffset = null
                     )
                 )
-            }
+            )
+        }
 
-        // wait for the client to enqueue message and handle message
-        Thread.sleep(Duration.ofMillis(1000).toMillis())
-        Shadows.shadowOf(Looper.getMainLooper()).idleFor(Duration.ofMillis(1000))
+        advanceUntilIdle()
+        waitForMainLooperIdle()
 
-        val response = runBlocking { deferred.await() }
+        val response = deferred.await()
         assertThat(response.recordUidsList).containsExactly("0")
         assertThat(fakeAhpServiceStub.dataStore.toList())
             .containsExactly(
@@ -169,26 +167,24 @@
             )
     }
 
-    @Test(timeout = 60000L)
-    fun insertRecords_weight() {
-        val deferred =
-            CoroutineScope(Dispatchers.Default).async {
-                healthConnectClient.insertRecords(
-                    listOf(
-                        Weight(
-                            weightKg = 45.8,
-                            time = Instant.ofEpochMilli(1234L),
-                            zoneOffset = null,
-                        )
+    @Test(timeout = 10000L)
+    fun insertRecords_weight() = runTest {
+        val deferred = async {
+            healthDataClient.insertRecords(
+                listOf(
+                    Weight(
+                        weightKg = 45.8,
+                        time = Instant.ofEpochMilli(1234L),
+                        zoneOffset = null,
                     )
                 )
-            }
+            )
+        }
 
-        // wait for the client to enqueue message and handle message
-        Thread.sleep(Duration.ofMillis(1000).toMillis())
-        Shadows.shadowOf(Looper.getMainLooper()).idleFor(Duration.ofMillis(1000))
+        advanceUntilIdle()
+        waitForMainLooperIdle()
 
-        val response = runBlocking { deferred.await() }
+        val response = deferred.await()
         assertThat(response.recordUidsList).containsExactly("0")
         assertThat(fakeAhpServiceStub.dataStore.toList())
             .containsExactly(
@@ -200,29 +196,27 @@
             )
     }
 
-    @Test(timeout = 60000L)
-    fun insertRecords_nutrition() {
-        val deferred =
-            CoroutineScope(Dispatchers.Default).async {
-                healthConnectClient.insertRecords(
-                    listOf(
-                        Nutrition(
-                            vitaminE = 10.0,
-                            vitaminC = 20.0,
-                            startTime = Instant.ofEpochMilli(1234L),
-                            startZoneOffset = null,
-                            endTime = Instant.ofEpochMilli(5678L),
-                            endZoneOffset = null
-                        )
+    @Test(timeout = 10000L)
+    fun insertRecords_nutrition() = runTest {
+        val deferred = async {
+            healthDataClient.insertRecords(
+                listOf(
+                    Nutrition(
+                        vitaminE = 10.0,
+                        vitaminC = 20.0,
+                        startTime = Instant.ofEpochMilli(1234L),
+                        startZoneOffset = null,
+                        endTime = Instant.ofEpochMilli(5678L),
+                        endZoneOffset = null
                     )
                 )
-            }
+            )
+        }
 
-        // wait for the client to enqueue message and handle message
-        Thread.sleep(Duration.ofMillis(1000).toMillis())
-        Shadows.shadowOf(Looper.getMainLooper()).idleFor(Duration.ofMillis(1000))
+        advanceUntilIdle()
+        waitForMainLooperIdle()
 
-        val response = runBlocking { deferred.await() }
+        val response = deferred.await()
         assertThat(response.recordUidsList).containsExactly("0")
         assertThat(fakeAhpServiceStub.dataStore.toList())
             .containsExactly(
@@ -236,6 +230,10 @@
             )
     }
 
+    private fun waitForMainLooperIdle() {
+        Shadows.shadowOf(Looper.getMainLooper()).idle()
+    }
+
     private fun installPackage(context: Context, packageName: String, enabled: Boolean) {
         val packageInfo = PackageInfo()
         packageInfo.packageName = packageName
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/AllRecordsConverterTest.kt b/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/AllRecordsConverterTest.kt
index 1e084be..40ec756 100644
--- a/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/AllRecordsConverterTest.kt
+++ b/health/health-data-client/src/test/java/androidx/health/data/client/impl/converters/records/AllRecordsConverterTest.kt
@@ -58,7 +58,6 @@
 import androidx.health.data.client.records.OvulationTest
 import androidx.health.data.client.records.OvulationTestResults
 import androidx.health.data.client.records.OxygenSaturation
-import androidx.health.data.client.records.Pace
 import androidx.health.data.client.records.Power
 import androidx.health.data.client.records.Repetitions
 import androidx.health.data.client.records.RespiratoryRate
@@ -76,6 +75,7 @@
 import androidx.health.data.client.records.Vo2Max
 import androidx.health.data.client.records.WaistCircumference
 import androidx.health.data.client.records.Weight
+import androidx.health.data.client.records.WheelchairPushes
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
 import java.time.Instant
@@ -439,19 +439,6 @@
     }
 
     @Test
-    fun testPace() {
-        val data =
-            Pace(
-                pace = 1.0,
-                time = START_TIME,
-                zoneOffset = END_ZONE_OFFSET,
-                metadata = TEST_METADATA
-            )
-
-        assertThat(toRecord(data.toProto())).isEqualTo(data)
-    }
-
-    @Test
     fun testPower() {
         val data =
             Power(
@@ -839,4 +826,19 @@
 
         assertThat(toRecord(data.toProto())).isEqualTo(data)
     }
+
+    @Test
+    fun testWheelchairPushes() {
+        val data =
+            WheelchairPushes(
+                count = 1,
+                startTime = START_TIME,
+                startZoneOffset = START_ZONE_OFFSET,
+                endTime = END_TIME,
+                endZoneOffset = END_ZONE_OFFSET,
+                metadata = TEST_METADATA
+            )
+
+        assertThat(toRecord(data.toProto())).isEqualTo(data)
+    }
 }
diff --git a/health/health-data-client/src/test/java/androidx/health/data/client/request/ReadRecordsRequestTest.kt b/health/health-data-client/src/test/java/androidx/health/data/client/request/ReadRecordsRequestTest.kt
new file mode 100644
index 0000000..62b034d3
--- /dev/null
+++ b/health/health-data-client/src/test/java/androidx/health/data/client/request/ReadRecordsRequestTest.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.health.data.client.request
+
+import androidx.health.data.client.records.Steps
+import androidx.health.data.client.time.TimeRangeFilter
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import java.time.Instant
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ReadRecordsRequestTest {
+
+    private val closedTimeRange =
+        TimeRangeFilter.exact(Instant.ofEpochMilli(1234L), Instant.ofEpochMilli(1235L))
+
+    @Test
+    fun limitAndSizeTogether_throws() {
+        val exception =
+            assertThrows(IllegalArgumentException::class.java) {
+                ReadRecordsRequest(
+                    recordType = Steps::class,
+                    timeRangeFilter = TimeRangeFilter.empty(),
+                    limit = 10,
+                    pageSize = 10
+                )
+            }
+        assertEquals("pageSize and limit can't be used at the same time", exception.message)
+    }
+
+    @Test
+    fun openEndedTimeRange_withoutLimitOrPageSize_throws() {
+        val exception =
+            assertThrows(IllegalArgumentException::class.java) {
+                ReadRecordsRequest(
+                    recordType = Steps::class,
+                    timeRangeFilter = TimeRangeFilter.empty()
+                )
+            }
+        assertEquals(
+            "When timeRangeFilter is open-ended, either limit or pageSize must be set",
+            exception.message
+        )
+    }
+
+    @Test
+    fun openEndedTimeRange_withLimit_success() {
+        ReadRecordsRequest(
+            recordType = Steps::class,
+            timeRangeFilter = TimeRangeFilter.empty(),
+            limit = 10
+        )
+    }
+
+    @Test
+    fun openEndedTimeRange_withPageSize_success() {
+        ReadRecordsRequest(
+            recordType = Steps::class,
+            timeRangeFilter = TimeRangeFilter.empty(),
+            pageSize = 10
+        )
+    }
+
+    @Test
+    fun closedTimeRange_success() {
+        ReadRecordsRequest(recordType = Steps::class, timeRangeFilter = closedTimeRange)
+    }
+
+    @Test
+    fun pageTokenWithoutPageSize_throws() {
+        val exception =
+            assertThrows(IllegalArgumentException::class.java) {
+                ReadRecordsRequest(
+                    recordType = Steps::class,
+                    timeRangeFilter = closedTimeRange,
+                    pageToken = "token"
+                )
+            }
+        assertEquals("pageToken must be set with pageSize", exception.message)
+    }
+
+    @Test
+    fun pageTokenWithPageSize_success() {
+        ReadRecordsRequest(
+            recordType = Steps::class,
+            timeRangeFilter = closedTimeRange,
+            pageSize = 10,
+            pageToken = "token"
+        )
+    }
+}
diff --git a/libraryversions.toml b/libraryversions.toml
index d1f0280..9aa510d 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -1,5 +1,5 @@
 [versions]
-ACTIVITY = "1.5.0-alpha04"
+ACTIVITY = "1.5.0-alpha05"
 ADS_IDENTIFIER = "1.0.0-alpha05"
 ANNOTATION = "1.4.0-alpha03"
 ANNOTATION_EXPERIMENTAL = "1.3.0-alpha01"
@@ -15,38 +15,38 @@
 CAMERA = "1.1.0-beta03"
 CAMERA_PIPE = "1.0.0-alpha01"
 CARDVIEW = "1.1.0-alpha01"
-CAR_APP = "1.2.0-rc01"
+CAR_APP = "1.3.0-alpha01"
 COLLECTION = "1.3.0-alpha01"
 COLLECTION2 = "1.3.0-alpha01"
-COMPOSE = "1.2.0-alpha06"
-COMPOSE_MATERIAL3 = "1.0.0-alpha08"
+COMPOSE = "1.2.0-alpha07"
+COMPOSE_MATERIAL3 = "1.0.0-alpha09"
 CONTENTPAGER = "1.1.0-alpha01"
 COORDINATORLAYOUT = "1.3.0-alpha01"
-CORE = "1.8.0-alpha06"
+CORE = "1.8.0-alpha07"
 CORE_ANIMATION = "1.0.0-alpha03"
 CORE_ANIMATION_TESTING = "1.0.0-alpha03"
 CORE_APPDIGEST = "1.0.0-alpha01"
 CORE_GOOGLE_SHORTCUTS = "1.1.0-alpha02"
 CORE_I18N = "1.0.0-alpha01"
-CORE_PERFORMANCE = "1.0.0-alpha02"
+CORE_PERFORMANCE = "1.0.0-alpha03"
 CORE_REMOTEVIEWS = "1.0.0-alpha04"
 CORE_ROLE = "1.2.0-alpha01"
-CORE_SPLASHSCREEN = "1.0.0-beta02"
+CORE_SPLASHSCREEN = "1.0.0-beta03"
 CORE_UWB = "1.0.0-alpha01"
 CURSORADAPTER = "1.1.0-alpha01"
 CUSTOMVIEW = "1.2.0-alpha02"
-CUSTOMVIEW_POOLINGCONTAINER = "1.0.0-alpha01"
+CUSTOMVIEW_POOLINGCONTAINER = "1.0.0-alpha02"
 DATASTORE = "1.1.0-alpha01"
 DOCUMENTFILE = "1.1.0-alpha02"
-DRAGANDDROP = "1.0.0-beta01"
+DRAGANDDROP = "1.0.0-beta02"
 DRAWERLAYOUT = "1.2.0-alpha01"
 DYNAMICANIMATION = "1.1.0-alpha04"
 DYNAMICANIMATION_KTX = "1.0.0-alpha04"
 EMOJI = "1.2.0-alpha03"
-EMOJI2 = "1.2.0-alpha02"
+EMOJI2 = "1.2.0-alpha03"
 ENTERPRISE = "1.1.0-rc01"
 EXIFINTERFACE = "1.4.0-alpha01"
-FRAGMENT = "1.5.0-alpha04"
+FRAGMENT = "1.5.0-alpha05"
 FUTURES = "1.2.0-alpha01"
 GLANCE = "1.0.0-alpha04"
 GLANCE_TEMPLATE = "1.0.0-alpha01"
@@ -67,15 +67,15 @@
 LEANBACK_TAB = "1.1.0-beta01"
 LEGACY = "1.1.0-alpha01"
 LIBYUV = "0.1.0-dev01"
-LIFECYCLE = "2.5.0-alpha05"
+LIFECYCLE = "2.5.0-alpha06"
 LIFECYCLE_EXTENSIONS = "2.2.0"
-LIFECYCLE_VIEWMODEL_COMPOSE = "2.5.0-alpha05"
+LIFECYCLE_VIEWMODEL_COMPOSE = "2.5.0-alpha06"
 LOADER = "1.2.0-alpha01"
-MEDIA = "1.6.0-beta01"
+MEDIA = "1.6.0-beta02"
 MEDIA2 = "1.3.0-alpha01"
-MEDIAROUTER = "1.3.0-rc01"
+MEDIAROUTER = "1.4.0-alpha01"
 METRICS = "1.0.0-alpha02"
-NAVIGATION = "2.5.0-alpha04"
+NAVIGATION = "2.5.0-alpha05"
 PAGING = "3.2.0-alpha01"
 PAGING_COMPOSE = "1.0.0-alpha15"
 PALETTE = "1.1.0-alpha01"
@@ -108,7 +108,7 @@
 TESTEXT = "1.0.0-alpha01"
 TESTSCREENSHOT = "1.0.0-alpha01"
 TEXT = "1.0.0-alpha01"
-TEXTCLASSIFIER = "1.0.0-alpha04"
+TEXTCLASSIFIER = "1.0.0-alpha05"
 TRACING = "1.1.0-beta03"
 TRACING_PERFETTO = "1.0.0-alpha01"
 TRANSITION = "1.5.0-alpha01"
@@ -120,13 +120,13 @@
 VIEWPAGER = "1.1.0-alpha02"
 VIEWPAGER2 = "1.1.0-beta02"
 WEAR = "1.3.0-alpha03"
-WEAR_COMPOSE = "1.0.0-alpha19"
+WEAR_COMPOSE = "1.0.0-alpha20"
 WEAR_INPUT = "1.2.0-alpha03"
 WEAR_INPUT_TESTING = "1.2.0-alpha03"
 WEAR_ONGOING = "1.1.0-alpha01"
 WEAR_PHONE_INTERACTIONS = "1.1.0-alpha04"
 WEAR_REMOTE_INTERACTIONS = "1.1.0-alpha01"
-WEAR_TILES = "1.1.0-alpha04"
+WEAR_TILES = "1.1.0-alpha05"
 WEAR_WATCHFACE = "1.1.0-alpha05"
 WEBKIT = "1.5.0-alpha01"
 WINDOW = "1.1.0-alpha01"
diff --git a/lint-checks/src/main/java/androidx/build/lint/BanUncheckedReflection.kt b/lint-checks/src/main/java/androidx/build/lint/BanUncheckedReflection.kt
index 6914489..62f8608 100644
--- a/lint-checks/src/main/java/androidx/build/lint/BanUncheckedReflection.kt
+++ b/lint-checks/src/main/java/androidx/build/lint/BanUncheckedReflection.kt
@@ -23,11 +23,11 @@
 import com.android.tools.lint.detector.api.Issue
 import com.android.tools.lint.detector.api.JavaContext
 import com.android.tools.lint.detector.api.Scope
-import com.android.tools.lint.checks.VersionChecks.Companion.isWithinVersionCheckConditional
 import com.android.sdklib.SdkVersionInfo.HIGHEST_KNOWN_API
 import com.android.tools.lint.detector.api.Incident
 import com.android.tools.lint.detector.api.Severity
 import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.android.tools.lint.detector.api.VersionChecks
 import com.intellij.psi.PsiMethod
 import org.jetbrains.uast.UCallExpression
 
@@ -51,8 +51,13 @@
         if (!context.evaluator.isMemberInClass(method, METHOD_REFLECTION_CLASS)) return
 
         // Flag if the call isn't inside an SDK_INT check.
-        if (!isWithinVersionCheckConditional(context, node, HIGHEST_KNOWN_API, false) &&
-            !isWithinVersionCheckConditional(context, node, 1, true)
+        if (!VersionChecks.isWithinVersionCheckConditional(
+                context,
+                node,
+                HIGHEST_KNOWN_API,
+                false
+            ) &&
+            !VersionChecks.isWithinVersionCheckConditional(context, node, 1, true)
         ) {
             val incident = Incident(context)
                 .issue(ISSUE)
diff --git a/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt b/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt
index 6d40535..781aa7d 100644
--- a/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt
+++ b/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt
@@ -19,7 +19,6 @@
 package androidx.build.lint
 
 import com.android.SdkConstants.ATTR_VALUE
-import com.android.tools.lint.checks.ApiDetector.Companion.REQUIRES_API_ANNOTATION
 import com.android.tools.lint.checks.ApiLookup
 import com.android.tools.lint.checks.ApiLookup.equivalentName
 import com.android.tools.lint.checks.DesugaredMethodLookup
@@ -39,6 +38,8 @@
 import com.android.tools.lint.detector.api.Severity
 import com.android.tools.lint.detector.api.SourceCodeScanner
 import com.android.tools.lint.detector.api.UastLintUtils.Companion.getLongAttribute
+import com.android.tools.lint.detector.api.VersionChecks
+import com.android.tools.lint.detector.api.VersionChecks.Companion.REQUIRES_API_ANNOTATION
 import com.android.tools.lint.detector.api.getInternalMethodName
 import com.android.tools.lint.detector.api.isKotlin
 import com.intellij.psi.PsiAnonymousClass
@@ -815,7 +816,7 @@
                                         return api
                                     }
                                 } else {
-                                    return codeNameToApi(name)
+                                    return VersionChecks.codeNameToApi(name)
                                 }
                             }
                         }
diff --git a/media/media/api/1.6.0-beta02.txt b/media/media/api/1.6.0-beta02.txt
new file mode 100644
index 0000000..89e9bd3
--- /dev/null
+++ b/media/media/api/1.6.0-beta02.txt
@@ -0,0 +1,751 @@
+// Signature format: 4.0
+package android.support.v4.media {
+
+  public final class MediaBrowserCompat {
+    ctor public MediaBrowserCompat(android.content.Context!, android.content.ComponentName!, android.support.v4.media.MediaBrowserCompat.ConnectionCallback!, android.os.Bundle!);
+    method public void connect();
+    method public void disconnect();
+    method public android.os.Bundle? getExtras();
+    method public void getItem(String, android.support.v4.media.MediaBrowserCompat.ItemCallback);
+    method public String getRoot();
+    method public android.content.ComponentName getServiceComponent();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public boolean isConnected();
+    method public void search(String, android.os.Bundle!, android.support.v4.media.MediaBrowserCompat.SearchCallback);
+    method public void sendCustomAction(String, android.os.Bundle!, android.support.v4.media.MediaBrowserCompat.CustomActionCallback?);
+    method public void subscribe(String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    method public void subscribe(String, android.os.Bundle, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    method public void unsubscribe(String);
+    method public void unsubscribe(String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    field public static final String CUSTOM_ACTION_DOWNLOAD = "android.support.v4.media.action.DOWNLOAD";
+    field public static final String CUSTOM_ACTION_REMOVE_DOWNLOADED_FILE = "android.support.v4.media.action.REMOVE_DOWNLOADED_FILE";
+    field public static final String EXTRA_DOWNLOAD_PROGRESS = "android.media.browse.extra.DOWNLOAD_PROGRESS";
+    field public static final String EXTRA_MEDIA_ID = "android.media.browse.extra.MEDIA_ID";
+    field public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
+    field public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
+  }
+
+  public static class MediaBrowserCompat.ConnectionCallback {
+    ctor public MediaBrowserCompat.ConnectionCallback();
+    method public void onConnected();
+    method public void onConnectionFailed();
+    method public void onConnectionSuspended();
+  }
+
+  public abstract static class MediaBrowserCompat.CustomActionCallback {
+    ctor public MediaBrowserCompat.CustomActionCallback();
+    method public void onError(String!, android.os.Bundle!, android.os.Bundle!);
+    method public void onProgressUpdate(String!, android.os.Bundle!, android.os.Bundle!);
+    method public void onResult(String!, android.os.Bundle!, android.os.Bundle!);
+  }
+
+  public abstract static class MediaBrowserCompat.ItemCallback {
+    ctor public MediaBrowserCompat.ItemCallback();
+    method public void onError(String);
+    method public void onItemLoaded(android.support.v4.media.MediaBrowserCompat.MediaItem!);
+  }
+
+  public static class MediaBrowserCompat.MediaItem implements android.os.Parcelable {
+    ctor public MediaBrowserCompat.MediaItem(android.support.v4.media.MediaDescriptionCompat, int);
+    method public int describeContents();
+    method public static android.support.v4.media.MediaBrowserCompat.MediaItem! fromMediaItem(Object!);
+    method public static java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>! fromMediaItemList(java.util.List<?>!);
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public int getFlags();
+    method public String? getMediaId();
+    method public boolean isBrowsable();
+    method public boolean isPlayable();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaBrowserCompat.MediaItem!>! CREATOR;
+    field public static final int FLAG_BROWSABLE = 1; // 0x1
+    field public static final int FLAG_PLAYABLE = 2; // 0x2
+  }
+
+  public abstract static class MediaBrowserCompat.SearchCallback {
+    ctor public MediaBrowserCompat.SearchCallback();
+    method public void onError(String, android.os.Bundle!);
+    method public void onSearchResult(String, android.os.Bundle!, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+  }
+
+  public abstract static class MediaBrowserCompat.SubscriptionCallback {
+    ctor public MediaBrowserCompat.SubscriptionCallback();
+    method public void onChildrenLoaded(String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+    method public void onChildrenLoaded(String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>, android.os.Bundle);
+    method public void onError(String);
+    method public void onError(String, android.os.Bundle);
+  }
+
+  public final class MediaDescriptionCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.MediaDescriptionCompat! fromMediaDescription(Object!);
+    method public CharSequence? getDescription();
+    method public android.os.Bundle? getExtras();
+    method public android.graphics.Bitmap? getIconBitmap();
+    method public android.net.Uri? getIconUri();
+    method public Object! getMediaDescription();
+    method public String? getMediaId();
+    method public android.net.Uri? getMediaUri();
+    method public CharSequence? getSubtitle();
+    method public CharSequence? getTitle();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
+    field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
+    field public static final long BT_FOLDER_TYPE_GENRES = 4L; // 0x4L
+    field public static final long BT_FOLDER_TYPE_MIXED = 0L; // 0x0L
+    field public static final long BT_FOLDER_TYPE_PLAYLISTS = 5L; // 0x5L
+    field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
+    field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaDescriptionCompat!>! CREATOR;
+    field public static final String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
+    field public static final String EXTRA_DOWNLOAD_STATUS = "android.media.extra.DOWNLOAD_STATUS";
+    field public static final long STATUS_DOWNLOADED = 2L; // 0x2L
+    field public static final long STATUS_DOWNLOADING = 1L; // 0x1L
+    field public static final long STATUS_NOT_DOWNLOADED = 0L; // 0x0L
+  }
+
+  public static final class MediaDescriptionCompat.Builder {
+    ctor public MediaDescriptionCompat.Builder();
+    method public android.support.v4.media.MediaDescriptionCompat! build();
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setDescription(CharSequence?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setExtras(android.os.Bundle?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setIconBitmap(android.graphics.Bitmap?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setIconUri(android.net.Uri?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setMediaId(String?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setMediaUri(android.net.Uri?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setSubtitle(CharSequence?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setTitle(CharSequence?);
+  }
+
+  public final class MediaMetadataCompat implements android.os.Parcelable {
+    method public boolean containsKey(String!);
+    method public int describeContents();
+    method public static android.support.v4.media.MediaMetadataCompat! fromMediaMetadata(Object!);
+    method public android.graphics.Bitmap! getBitmap(String!);
+    method public android.os.Bundle! getBundle();
+    method public android.support.v4.media.MediaDescriptionCompat! getDescription();
+    method public long getLong(String!);
+    method public Object! getMediaMetadata();
+    method public android.support.v4.media.RatingCompat! getRating(String!);
+    method public String! getString(String!);
+    method public CharSequence! getText(String!);
+    method public java.util.Set<java.lang.String!>! keySet();
+    method public int size();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaMetadataCompat!>! CREATOR;
+    field public static final String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+    field public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+    field public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+    field public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+    field public static final String METADATA_KEY_ART = "android.media.metadata.ART";
+    field public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+    field public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
+    field public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+    field public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
+    field public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+    field public static final String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+    field public static final String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+    field public static final String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+    field public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+    field public static final String METADATA_KEY_DOWNLOAD_STATUS = "android.media.metadata.DOWNLOAD_STATUS";
+    field public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+    field public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+    field public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
+    field public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+    field public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
+    field public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+    field public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+    field public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+  }
+
+  public static final class MediaMetadataCompat.Builder {
+    ctor public MediaMetadataCompat.Builder();
+    ctor public MediaMetadataCompat.Builder(android.support.v4.media.MediaMetadataCompat!);
+    method public android.support.v4.media.MediaMetadataCompat! build();
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putBitmap(String!, android.graphics.Bitmap!);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putLong(String!, long);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putRating(String!, android.support.v4.media.RatingCompat!);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putString(String!, String!);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putText(String!, CharSequence!);
+  }
+
+  public final class RatingCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.RatingCompat! fromRating(Object!);
+    method public float getPercentRating();
+    method public Object! getRating();
+    method public int getRatingStyle();
+    method public float getStarRating();
+    method public boolean hasHeart();
+    method public boolean isRated();
+    method public boolean isThumbUp();
+    method public static android.support.v4.media.RatingCompat! newHeartRating(boolean);
+    method public static android.support.v4.media.RatingCompat! newPercentageRating(float);
+    method public static android.support.v4.media.RatingCompat! newStarRating(int, float);
+    method public static android.support.v4.media.RatingCompat! newThumbRating(boolean);
+    method public static android.support.v4.media.RatingCompat! newUnratedRating(int);
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.RatingCompat!>! CREATOR;
+    field public static final int RATING_3_STARS = 3; // 0x3
+    field public static final int RATING_4_STARS = 4; // 0x4
+    field public static final int RATING_5_STARS = 5; // 0x5
+    field public static final int RATING_HEART = 1; // 0x1
+    field public static final int RATING_NONE = 0; // 0x0
+    field public static final int RATING_PERCENTAGE = 6; // 0x6
+    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+  }
+
+}
+
+package android.support.v4.media.session {
+
+  public final class MediaControllerCompat {
+    ctor public MediaControllerCompat(android.content.Context!, android.support.v4.media.session.MediaSessionCompat);
+    ctor public MediaControllerCompat(android.content.Context!, android.support.v4.media.session.MediaSessionCompat.Token);
+    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat!, int);
+    method public void adjustVolume(int, int);
+    method public boolean dispatchMediaButtonEvent(android.view.KeyEvent!);
+    method public android.os.Bundle! getExtras();
+    method public long getFlags();
+    method public static android.support.v4.media.session.MediaControllerCompat! getMediaController(android.app.Activity);
+    method public Object! getMediaController();
+    method public android.support.v4.media.MediaMetadataCompat! getMetadata();
+    method public String! getPackageName();
+    method public android.support.v4.media.session.MediaControllerCompat.PlaybackInfo! getPlaybackInfo();
+    method public android.support.v4.media.session.PlaybackStateCompat! getPlaybackState();
+    method public java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! getQueue();
+    method public CharSequence! getQueueTitle();
+    method public int getRatingType();
+    method public int getRepeatMode();
+    method public android.app.PendingIntent! getSessionActivity();
+    method public android.os.Bundle getSessionInfo();
+    method public android.support.v4.media.session.MediaSessionCompat.Token! getSessionToken();
+    method public int getShuffleMode();
+    method public android.support.v4.media.session.MediaControllerCompat.TransportControls! getTransportControls();
+    method public boolean isCaptioningEnabled();
+    method public boolean isSessionReady();
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler!);
+    method public void removeQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method @Deprecated public void removeQueueItemAt(int);
+    method public void sendCommand(String, android.os.Bundle?, android.os.ResultReceiver?);
+    method public static void setMediaController(android.app.Activity, android.support.v4.media.session.MediaControllerCompat!);
+    method public void setVolumeTo(int, int);
+    method public void unregisterCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+  }
+
+  public abstract static class MediaControllerCompat.Callback implements android.os.IBinder.DeathRecipient {
+    ctor public MediaControllerCompat.Callback();
+    method public void binderDied();
+    method public void onAudioInfoChanged(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo!);
+    method public void onCaptioningEnabledChanged(boolean);
+    method public void onExtrasChanged(android.os.Bundle!);
+    method public void onMetadataChanged(android.support.v4.media.MediaMetadataCompat!);
+    method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat!);
+    method public void onQueueChanged(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>!);
+    method public void onQueueTitleChanged(CharSequence!);
+    method public void onRepeatModeChanged(int);
+    method public void onSessionDestroyed();
+    method public void onSessionEvent(String!, android.os.Bundle!);
+    method public void onSessionReady();
+    method public void onShuffleModeChanged(int);
+  }
+
+  public static final class MediaControllerCompat.PlaybackInfo {
+    method public androidx.media.AudioAttributesCompat getAudioAttributes();
+    method @Deprecated public int getAudioStream();
+    method public int getCurrentVolume();
+    method public int getMaxVolume();
+    method public int getPlaybackType();
+    method public int getVolumeControl();
+    field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
+    field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
+  }
+
+  public abstract static class MediaControllerCompat.TransportControls {
+    method public abstract void fastForward();
+    method public abstract void pause();
+    method public abstract void play();
+    method public abstract void playFromMediaId(String!, android.os.Bundle!);
+    method public abstract void playFromSearch(String!, android.os.Bundle!);
+    method public abstract void playFromUri(android.net.Uri!, android.os.Bundle!);
+    method public abstract void prepare();
+    method public abstract void prepareFromMediaId(String!, android.os.Bundle!);
+    method public abstract void prepareFromSearch(String!, android.os.Bundle!);
+    method public abstract void prepareFromUri(android.net.Uri!, android.os.Bundle!);
+    method public abstract void rewind();
+    method public abstract void seekTo(long);
+    method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction!, android.os.Bundle!);
+    method public abstract void sendCustomAction(String!, android.os.Bundle!);
+    method public abstract void setCaptioningEnabled(boolean);
+    method public void setPlaybackSpeed(float);
+    method public abstract void setRating(android.support.v4.media.RatingCompat!);
+    method public abstract void setRating(android.support.v4.media.RatingCompat!, android.os.Bundle!);
+    method public abstract void setRepeatMode(int);
+    method public abstract void setShuffleMode(int);
+    method public abstract void skipToNext();
+    method public abstract void skipToPrevious();
+    method public abstract void skipToQueueItem(long);
+    method public abstract void stop();
+    field @Deprecated public static final String EXTRA_LEGACY_STREAM_TYPE = "android.media.session.extra.LEGACY_STREAM_TYPE";
+  }
+
+  public class MediaSessionCompat {
+    ctor public MediaSessionCompat(android.content.Context, String);
+    ctor public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?);
+    ctor public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?, android.os.Bundle?);
+    method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener!);
+    method public static android.support.v4.media.session.MediaSessionCompat! fromMediaSession(android.content.Context!, Object!);
+    method public android.support.v4.media.session.MediaControllerCompat! getController();
+    method public final androidx.media.MediaSessionManager.RemoteUserInfo getCurrentControllerInfo();
+    method public Object! getMediaSession();
+    method public Object! getRemoteControlClient();
+    method public android.support.v4.media.session.MediaSessionCompat.Token! getSessionToken();
+    method public boolean isActive();
+    method public void release();
+    method public void removeOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener!);
+    method public void sendSessionEvent(String!, android.os.Bundle!);
+    method public void setActive(boolean);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback!);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback!, android.os.Handler!);
+    method public void setCaptioningEnabled(boolean);
+    method public void setExtras(android.os.Bundle!);
+    method public void setFlags(int);
+    method public void setMediaButtonReceiver(android.app.PendingIntent!);
+    method public void setMetadata(android.support.v4.media.MediaMetadataCompat!);
+    method public void setPlaybackState(android.support.v4.media.session.PlaybackStateCompat!);
+    method public void setPlaybackToLocal(int);
+    method public void setPlaybackToRemote(androidx.media.VolumeProviderCompat!);
+    method public void setQueue(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>!);
+    method public void setQueueTitle(CharSequence!);
+    method public void setRatingType(int);
+    method public void setRepeatMode(int);
+    method public void setSessionActivity(android.app.PendingIntent!);
+    method public void setShuffleMode(int);
+    field public static final String ACTION_FLAG_AS_INAPPROPRIATE = "android.support.v4.media.session.action.FLAG_AS_INAPPROPRIATE";
+    field public static final String ACTION_FOLLOW = "android.support.v4.media.session.action.FOLLOW";
+    field public static final String ACTION_SKIP_AD = "android.support.v4.media.session.action.SKIP_AD";
+    field public static final String ACTION_UNFOLLOW = "android.support.v4.media.session.action.UNFOLLOW";
+    field public static final String ARGUMENT_MEDIA_ATTRIBUTE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE";
+    field public static final String ARGUMENT_MEDIA_ATTRIBUTE_VALUE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE_VALUE";
+    field @Deprecated public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
+    field @Deprecated public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+    field public static final int MEDIA_ATTRIBUTE_ALBUM = 1; // 0x1
+    field public static final int MEDIA_ATTRIBUTE_ARTIST = 0; // 0x0
+    field public static final int MEDIA_ATTRIBUTE_PLAYLIST = 2; // 0x2
+  }
+
+  public abstract static class MediaSessionCompat.Callback {
+    ctor public MediaSessionCompat.Callback();
+    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat!, int);
+    method public void onCommand(String!, android.os.Bundle!, android.os.ResultReceiver!);
+    method public void onCustomAction(String!, android.os.Bundle!);
+    method public void onFastForward();
+    method public boolean onMediaButtonEvent(android.content.Intent!);
+    method public void onPause();
+    method public void onPlay();
+    method public void onPlayFromMediaId(String!, android.os.Bundle!);
+    method public void onPlayFromSearch(String!, android.os.Bundle!);
+    method public void onPlayFromUri(android.net.Uri!, android.os.Bundle!);
+    method public void onPrepare();
+    method public void onPrepareFromMediaId(String!, android.os.Bundle!);
+    method public void onPrepareFromSearch(String!, android.os.Bundle!);
+    method public void onPrepareFromUri(android.net.Uri!, android.os.Bundle!);
+    method public void onRemoveQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method @Deprecated public void onRemoveQueueItemAt(int);
+    method public void onRewind();
+    method public void onSeekTo(long);
+    method public void onSetCaptioningEnabled(boolean);
+    method public void onSetPlaybackSpeed(float);
+    method public void onSetRating(android.support.v4.media.RatingCompat!);
+    method public void onSetRating(android.support.v4.media.RatingCompat!, android.os.Bundle!);
+    method public void onSetRepeatMode(int);
+    method public void onSetShuffleMode(int);
+    method public void onSkipToNext();
+    method public void onSkipToPrevious();
+    method public void onSkipToQueueItem(long);
+    method public void onStop();
+  }
+
+  public static interface MediaSessionCompat.OnActiveChangeListener {
+    method public void onActiveChanged();
+  }
+
+  public static final class MediaSessionCompat.QueueItem implements android.os.Parcelable {
+    ctor public MediaSessionCompat.QueueItem(android.support.v4.media.MediaDescriptionCompat!, long);
+    method public int describeContents();
+    method public static android.support.v4.media.session.MediaSessionCompat.QueueItem! fromQueueItem(Object!);
+    method public static java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! fromQueueItemList(java.util.List<?>!);
+    method public android.support.v4.media.MediaDescriptionCompat! getDescription();
+    method public long getQueueId();
+    method public Object! getQueueItem();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! CREATOR;
+    field public static final int UNKNOWN_ID = -1; // 0xffffffff
+  }
+
+  public static final class MediaSessionCompat.Token implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.MediaSessionCompat.Token! fromToken(Object!);
+    method public Object! getToken();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.Token!>! CREATOR;
+  }
+
+  public class ParcelableVolumeInfo implements android.os.Parcelable {
+    ctor public ParcelableVolumeInfo(int, int, int, int, int);
+    ctor public ParcelableVolumeInfo(android.os.Parcel!);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.ParcelableVolumeInfo!>! CREATOR;
+    field public int audioStream;
+    field public int controlType;
+    field public int currentVolume;
+    field public int maxVolume;
+    field public int volumeType;
+  }
+
+  public final class PlaybackStateCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat! fromPlaybackState(Object!);
+    method public long getActions();
+    method public long getActiveQueueItemId();
+    method public long getBufferedPosition();
+    method public java.util.List<android.support.v4.media.session.PlaybackStateCompat.CustomAction!>! getCustomActions();
+    method public int getErrorCode();
+    method public CharSequence! getErrorMessage();
+    method public android.os.Bundle? getExtras();
+    method public long getLastPositionUpdateTime();
+    method public float getPlaybackSpeed();
+    method public Object! getPlaybackState();
+    method public long getPosition();
+    method public int getState();
+    method public static int toKeyCode(long);
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
+    field public static final long ACTION_PAUSE = 2L; // 0x2L
+    field public static final long ACTION_PLAY = 4L; // 0x4L
+    field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
+    field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+    field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
+    field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+    field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+    field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+    field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+    field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
+    field public static final long ACTION_REWIND = 8L; // 0x8L
+    field public static final long ACTION_SEEK_TO = 256L; // 0x100L
+    field public static final long ACTION_SET_CAPTIONING_ENABLED = 1048576L; // 0x100000L
+    field public static final long ACTION_SET_PLAYBACK_SPEED = 4194304L; // 0x400000L
+    field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
+    field public static final long ACTION_SET_SHUFFLE_MODE = 2097152L; // 0x200000L
+    field @Deprecated public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
+    field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
+    field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
+    field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
+    field public static final long ACTION_STOP = 1L; // 0x1L
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat!>! CREATOR;
+    field public static final int ERROR_CODE_ACTION_ABORTED = 10; // 0xa
+    field public static final int ERROR_CODE_APP_ERROR = 1; // 0x1
+    field public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; // 0x3
+    field public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; // 0x5
+    field public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; // 0x8
+    field public static final int ERROR_CODE_END_OF_QUEUE = 11; // 0xb
+    field public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; // 0x7
+    field public static final int ERROR_CODE_NOT_SUPPORTED = 2; // 0x2
+    field public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; // 0x6
+    field public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; // 0x4
+    field public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; // 0x9
+    field public static final int ERROR_CODE_UNKNOWN_ERROR = 0; // 0x0
+    field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+    field public static final int REPEAT_MODE_ALL = 2; // 0x2
+    field public static final int REPEAT_MODE_GROUP = 3; // 0x3
+    field public static final int REPEAT_MODE_INVALID = -1; // 0xffffffff
+    field public static final int REPEAT_MODE_NONE = 0; // 0x0
+    field public static final int REPEAT_MODE_ONE = 1; // 0x1
+    field public static final int SHUFFLE_MODE_ALL = 1; // 0x1
+    field public static final int SHUFFLE_MODE_GROUP = 2; // 0x2
+    field public static final int SHUFFLE_MODE_INVALID = -1; // 0xffffffff
+    field public static final int SHUFFLE_MODE_NONE = 0; // 0x0
+    field public static final int STATE_BUFFERING = 6; // 0x6
+    field public static final int STATE_CONNECTING = 8; // 0x8
+    field public static final int STATE_ERROR = 7; // 0x7
+    field public static final int STATE_FAST_FORWARDING = 4; // 0x4
+    field public static final int STATE_NONE = 0; // 0x0
+    field public static final int STATE_PAUSED = 2; // 0x2
+    field public static final int STATE_PLAYING = 3; // 0x3
+    field public static final int STATE_REWINDING = 5; // 0x5
+    field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
+    field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
+    field public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; // 0xb
+    field public static final int STATE_STOPPED = 1; // 0x1
+  }
+
+  public static final class PlaybackStateCompat.Builder {
+    ctor public PlaybackStateCompat.Builder();
+    ctor public PlaybackStateCompat.Builder(android.support.v4.media.session.PlaybackStateCompat!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! addCustomAction(String!, String!, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! addCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction!);
+    method public android.support.v4.media.session.PlaybackStateCompat! build();
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setActions(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setActiveQueueItemId(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setBufferedPosition(long);
+    method @Deprecated public android.support.v4.media.session.PlaybackStateCompat.Builder! setErrorMessage(CharSequence!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setErrorMessage(int, CharSequence!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setExtras(android.os.Bundle!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setState(int, long, float);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setState(int, long, float, long);
+  }
+
+  public static final class PlaybackStateCompat.CustomAction implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat.CustomAction! fromCustomAction(Object!);
+    method public String! getAction();
+    method public Object! getCustomAction();
+    method public android.os.Bundle! getExtras();
+    method public int getIcon();
+    method public CharSequence! getName();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat.CustomAction!>! CREATOR;
+  }
+
+  public static final class PlaybackStateCompat.CustomAction.Builder {
+    ctor public PlaybackStateCompat.CustomAction.Builder(String!, CharSequence!, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction! build();
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction.Builder! setExtras(android.os.Bundle!);
+  }
+
+}
+
+package androidx.media {
+
+  public class AudioAttributesCompat implements androidx.versionedparcelable.VersionedParcelable {
+    method public int getContentType();
+    method public int getFlags();
+    method public int getLegacyStreamType();
+    method public int getUsage();
+    method public int getVolumeControlStream();
+    method public Object? unwrap();
+    method public static androidx.media.AudioAttributesCompat? wrap(Object);
+    field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
+    field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
+    field public static final int CONTENT_TYPE_SONIFICATION = 4; // 0x4
+    field public static final int CONTENT_TYPE_SPEECH = 1; // 0x1
+    field public static final int CONTENT_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
+    field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
+    field public static final int USAGE_ALARM = 4; // 0x4
+    field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
+    field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
+    field public static final int USAGE_ASSISTANCE_SONIFICATION = 13; // 0xd
+    field public static final int USAGE_ASSISTANT = 16; // 0x10
+    field public static final int USAGE_GAME = 14; // 0xe
+    field public static final int USAGE_MEDIA = 1; // 0x1
+    field public static final int USAGE_NOTIFICATION = 5; // 0x5
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9; // 0x9
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8; // 0x8
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7; // 0x7
+    field public static final int USAGE_NOTIFICATION_EVENT = 10; // 0xa
+    field public static final int USAGE_NOTIFICATION_RINGTONE = 6; // 0x6
+    field public static final int USAGE_UNKNOWN = 0; // 0x0
+    field public static final int USAGE_VOICE_COMMUNICATION = 2; // 0x2
+    field public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3; // 0x3
+  }
+
+  public static class AudioAttributesCompat.Builder {
+    ctor public AudioAttributesCompat.Builder();
+    ctor public AudioAttributesCompat.Builder(androidx.media.AudioAttributesCompat!);
+    method public androidx.media.AudioAttributesCompat! build();
+    method public androidx.media.AudioAttributesCompat.Builder! setContentType(int);
+    method public androidx.media.AudioAttributesCompat.Builder! setFlags(int);
+    method public androidx.media.AudioAttributesCompat.Builder! setLegacyStreamType(int);
+    method public androidx.media.AudioAttributesCompat.Builder! setUsage(int);
+  }
+
+  public class AudioFocusRequestCompat {
+    method public androidx.media.AudioAttributesCompat getAudioAttributesCompat();
+    method public android.os.Handler getFocusChangeHandler();
+    method public int getFocusGain();
+    method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
+    method public boolean willPauseWhenDucked();
+  }
+
+  public static final class AudioFocusRequestCompat.Builder {
+    ctor public AudioFocusRequestCompat.Builder(int);
+    ctor public AudioFocusRequestCompat.Builder(androidx.media.AudioFocusRequestCompat);
+    method public androidx.media.AudioFocusRequestCompat! build();
+    method public androidx.media.AudioFocusRequestCompat.Builder setAudioAttributes(androidx.media.AudioAttributesCompat);
+    method public androidx.media.AudioFocusRequestCompat.Builder setFocusGain(int);
+    method public androidx.media.AudioFocusRequestCompat.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener);
+    method public androidx.media.AudioFocusRequestCompat.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
+    method public androidx.media.AudioFocusRequestCompat.Builder setWillPauseWhenDucked(boolean);
+  }
+
+  public final class AudioManagerCompat {
+    method public static int abandonAudioFocusRequest(android.media.AudioManager, androidx.media.AudioFocusRequestCompat);
+    method @IntRange(from=0) public static int getStreamMaxVolume(android.media.AudioManager, int);
+    method @IntRange(from=0) public static int getStreamMinVolume(android.media.AudioManager, int);
+    method public static boolean isVolumeFixed(android.media.AudioManager);
+    method public static int requestAudioFocus(android.media.AudioManager, androidx.media.AudioFocusRequestCompat);
+    field public static final int AUDIOFOCUS_GAIN = 1; // 0x1
+    field public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; // 0x2
+    field public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; // 0x4
+    field public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; // 0x3
+  }
+
+  public abstract class MediaBrowserServiceCompat extends android.app.Service {
+    ctor public MediaBrowserServiceCompat();
+    method public void dump(java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+    method public final android.os.Bundle! getBrowserRootHints();
+    method public final androidx.media.MediaSessionManager.RemoteUserInfo getCurrentBrowserInfo();
+    method public android.support.v4.media.session.MediaSessionCompat.Token? getSessionToken();
+    method public void notifyChildrenChanged(String);
+    method public void notifyChildrenChanged(String, android.os.Bundle);
+    method public android.os.IBinder! onBind(android.content.Intent!);
+    method public void onCustomAction(String, android.os.Bundle!, androidx.media.MediaBrowserServiceCompat.Result<android.os.Bundle!>);
+    method public abstract androidx.media.MediaBrowserServiceCompat.BrowserRoot? onGetRoot(String, int, android.os.Bundle?);
+    method public abstract void onLoadChildren(String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>);
+    method public void onLoadChildren(String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>, android.os.Bundle);
+    method public void onLoadItem(String!, androidx.media.MediaBrowserServiceCompat.Result<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+    method public void onSearch(String, android.os.Bundle!, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>);
+    method public void setSessionToken(android.support.v4.media.session.MediaSessionCompat.Token!);
+    field public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+  }
+
+  public static final class MediaBrowserServiceCompat.BrowserRoot {
+    ctor public MediaBrowserServiceCompat.BrowserRoot(String, android.os.Bundle?);
+    method public android.os.Bundle! getExtras();
+    method public String! getRootId();
+    field public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+    field public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
+    field public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+    field @Deprecated public static final String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
+  }
+
+  public static class MediaBrowserServiceCompat.Result<T> {
+    method public void detach();
+    method public void sendError(android.os.Bundle?);
+    method public void sendProgressUpdate(android.os.Bundle?);
+    method public void sendResult(T?);
+  }
+
+  public final class MediaSessionManager {
+    method public static androidx.media.MediaSessionManager getSessionManager(android.content.Context);
+    method public boolean isTrustedForMediaControl(androidx.media.MediaSessionManager.RemoteUserInfo);
+  }
+
+  public static final class MediaSessionManager.RemoteUserInfo {
+    ctor public MediaSessionManager.RemoteUserInfo(String, int, int);
+    method public String getPackageName();
+    method public int getPid();
+    method public int getUid();
+    field public static final String LEGACY_CONTROLLER = "android.media.session.MediaController";
+  }
+
+  public abstract class VolumeProviderCompat {
+    ctor public VolumeProviderCompat(int, int, int);
+    method public final int getCurrentVolume();
+    method public final int getMaxVolume();
+    method public final int getVolumeControl();
+    method public Object! getVolumeProvider();
+    method public void onAdjustVolume(int);
+    method public void onSetVolumeTo(int);
+    method public void setCallback(androidx.media.VolumeProviderCompat.Callback!);
+    method public final void setCurrentVolume(int);
+    field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+    field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+    field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
+  }
+
+  public abstract static class VolumeProviderCompat.Callback {
+    ctor public VolumeProviderCompat.Callback();
+    method public abstract void onVolumeChanged(androidx.media.VolumeProviderCompat!);
+  }
+
+}
+
+package androidx.media.app {
+
+  public class NotificationCompat {
+  }
+
+  public static class NotificationCompat.DecoratedMediaCustomViewStyle extends androidx.media.app.NotificationCompat.MediaStyle {
+    ctor public NotificationCompat.DecoratedMediaCustomViewStyle();
+  }
+
+  public static class NotificationCompat.MediaStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.MediaStyle();
+    ctor public NotificationCompat.MediaStyle(androidx.core.app.NotificationCompat.Builder!);
+    method public static android.support.v4.media.session.MediaSessionCompat.Token! getMediaSession(android.app.Notification!);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setCancelButtonIntent(android.app.PendingIntent!);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setMediaSession(android.support.v4.media.session.MediaSessionCompat.Token!);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setShowActionsInCompactView(int...);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setShowCancelButton(boolean);
+  }
+
+}
+
+package androidx.media.session {
+
+  public class MediaButtonReceiver extends android.content.BroadcastReceiver {
+    ctor public MediaButtonReceiver();
+    method public static android.app.PendingIntent! buildMediaButtonPendingIntent(android.content.Context!, long);
+    method public static android.app.PendingIntent! buildMediaButtonPendingIntent(android.content.Context!, android.content.ComponentName!, long);
+    method public static android.view.KeyEvent! handleIntent(android.support.v4.media.session.MediaSessionCompat!, android.content.Intent!);
+    method public void onReceive(android.content.Context!, android.content.Intent!);
+  }
+
+}
+
+package androidx.media.utils {
+
+  public final class MediaConstants {
+    field public static final String BROWSER_ROOT_HINTS_KEY_MEDIA_ART_SIZE_PIXELS = "android.media.extras.MEDIA_ART_SIZE_HINT_PIXELS";
+    field public static final String BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT = "androidx.media.MediaBrowserCompat.Extras.KEY_ROOT_CHILDREN_LIMIT";
+    field public static final String BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS = "androidx.media.MediaBrowserCompat.Extras.KEY_ROOT_CHILDREN_SUPPORTED_FLAGS";
+    field public static final String BROWSER_SERVICE_EXTRAS_KEY_APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT = "androidx.media.BrowserRoot.Extras.APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT";
+    field public static final String BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED = "android.media.browse.SEARCH_SUPPORTED";
+    field public static final String DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE = "androidx.media.MediaItem.Extras.COMPLETION_PERCENTAGE";
+    field public static final String DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS = "android.media.extra.PLAYBACK_STATUS";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE = "android.media.browse.CONTENT_STYLE_BROWSABLE_HINT";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE = "android.media.browse.CONTENT_STYLE_GROUP_TITLE_HINT";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE = "android.media.browse.CONTENT_STYLE_PLAYABLE_HINT";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM = "android.media.browse.CONTENT_STYLE_SINGLE_ITEM_HINT";
+    field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED = 2; // 0x2
+    field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED = 0; // 0x0
+    field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED = 1; // 0x1
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM = 4; // 0x4
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM = 3; // 0x3
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM = 2; // 0x2
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM = 1; // 0x1
+    field public static final String METADATA_KEY_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_CONTENT_ID";
+    field public static final String METADATA_KEY_IS_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+    field public static final String METADATA_KEY_IS_EXPLICIT = "android.media.IS_EXPLICIT";
+    field public static final String METADATA_KEY_NEXT_EPISODE_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_NEXT_EPISODE_CONTENT_ID";
+    field public static final String METADATA_KEY_SERIES_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_SERIES_CONTENT_ID";
+    field public static final long METADATA_VALUE_ATTRIBUTE_PRESENT = 1L; // 0x1L
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT = "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT";
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL = "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL";
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT = "androidx.media.PlaybackStateCompat.Extras.ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT";
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID = "androidx.media.PlaybackStateCompat.Extras.KEY_MEDIA_ID";
+    field public static final String SESSION_EXTRAS_KEY_ACCOUNT_NAME = "androidx.media.MediaSessionCompat.Extras.KEY_ACCOUNT_NAME";
+    field public static final String SESSION_EXTRAS_KEY_ACCOUNT_TYPE = "androidx.media.MediaSessionCompat.Extras.KEY_ACCOUNT_TYPE";
+    field public static final String SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT = "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_NEXT";
+    field public static final String SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV = "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS";
+    field public static final String TRANSPORT_CONTROLS_EXTRAS_KEY_LEGACY_STREAM_TYPE = "android.media.session.extra.LEGACY_STREAM_TYPE";
+    field public static final String TRANSPORT_CONTROLS_EXTRAS_KEY_SHUFFLE = "androidx.media.MediaControllerCompat.TransportControls.extras.KEY_SHUFFLE";
+  }
+
+}
+
diff --git a/media/media/api/public_plus_experimental_1.6.0-beta02.txt b/media/media/api/public_plus_experimental_1.6.0-beta02.txt
new file mode 100644
index 0000000..89e9bd3
--- /dev/null
+++ b/media/media/api/public_plus_experimental_1.6.0-beta02.txt
@@ -0,0 +1,751 @@
+// Signature format: 4.0
+package android.support.v4.media {
+
+  public final class MediaBrowserCompat {
+    ctor public MediaBrowserCompat(android.content.Context!, android.content.ComponentName!, android.support.v4.media.MediaBrowserCompat.ConnectionCallback!, android.os.Bundle!);
+    method public void connect();
+    method public void disconnect();
+    method public android.os.Bundle? getExtras();
+    method public void getItem(String, android.support.v4.media.MediaBrowserCompat.ItemCallback);
+    method public String getRoot();
+    method public android.content.ComponentName getServiceComponent();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public boolean isConnected();
+    method public void search(String, android.os.Bundle!, android.support.v4.media.MediaBrowserCompat.SearchCallback);
+    method public void sendCustomAction(String, android.os.Bundle!, android.support.v4.media.MediaBrowserCompat.CustomActionCallback?);
+    method public void subscribe(String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    method public void subscribe(String, android.os.Bundle, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    method public void unsubscribe(String);
+    method public void unsubscribe(String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    field public static final String CUSTOM_ACTION_DOWNLOAD = "android.support.v4.media.action.DOWNLOAD";
+    field public static final String CUSTOM_ACTION_REMOVE_DOWNLOADED_FILE = "android.support.v4.media.action.REMOVE_DOWNLOADED_FILE";
+    field public static final String EXTRA_DOWNLOAD_PROGRESS = "android.media.browse.extra.DOWNLOAD_PROGRESS";
+    field public static final String EXTRA_MEDIA_ID = "android.media.browse.extra.MEDIA_ID";
+    field public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
+    field public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
+  }
+
+  public static class MediaBrowserCompat.ConnectionCallback {
+    ctor public MediaBrowserCompat.ConnectionCallback();
+    method public void onConnected();
+    method public void onConnectionFailed();
+    method public void onConnectionSuspended();
+  }
+
+  public abstract static class MediaBrowserCompat.CustomActionCallback {
+    ctor public MediaBrowserCompat.CustomActionCallback();
+    method public void onError(String!, android.os.Bundle!, android.os.Bundle!);
+    method public void onProgressUpdate(String!, android.os.Bundle!, android.os.Bundle!);
+    method public void onResult(String!, android.os.Bundle!, android.os.Bundle!);
+  }
+
+  public abstract static class MediaBrowserCompat.ItemCallback {
+    ctor public MediaBrowserCompat.ItemCallback();
+    method public void onError(String);
+    method public void onItemLoaded(android.support.v4.media.MediaBrowserCompat.MediaItem!);
+  }
+
+  public static class MediaBrowserCompat.MediaItem implements android.os.Parcelable {
+    ctor public MediaBrowserCompat.MediaItem(android.support.v4.media.MediaDescriptionCompat, int);
+    method public int describeContents();
+    method public static android.support.v4.media.MediaBrowserCompat.MediaItem! fromMediaItem(Object!);
+    method public static java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>! fromMediaItemList(java.util.List<?>!);
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public int getFlags();
+    method public String? getMediaId();
+    method public boolean isBrowsable();
+    method public boolean isPlayable();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaBrowserCompat.MediaItem!>! CREATOR;
+    field public static final int FLAG_BROWSABLE = 1; // 0x1
+    field public static final int FLAG_PLAYABLE = 2; // 0x2
+  }
+
+  public abstract static class MediaBrowserCompat.SearchCallback {
+    ctor public MediaBrowserCompat.SearchCallback();
+    method public void onError(String, android.os.Bundle!);
+    method public void onSearchResult(String, android.os.Bundle!, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+  }
+
+  public abstract static class MediaBrowserCompat.SubscriptionCallback {
+    ctor public MediaBrowserCompat.SubscriptionCallback();
+    method public void onChildrenLoaded(String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+    method public void onChildrenLoaded(String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>, android.os.Bundle);
+    method public void onError(String);
+    method public void onError(String, android.os.Bundle);
+  }
+
+  public final class MediaDescriptionCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.MediaDescriptionCompat! fromMediaDescription(Object!);
+    method public CharSequence? getDescription();
+    method public android.os.Bundle? getExtras();
+    method public android.graphics.Bitmap? getIconBitmap();
+    method public android.net.Uri? getIconUri();
+    method public Object! getMediaDescription();
+    method public String? getMediaId();
+    method public android.net.Uri? getMediaUri();
+    method public CharSequence? getSubtitle();
+    method public CharSequence? getTitle();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
+    field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
+    field public static final long BT_FOLDER_TYPE_GENRES = 4L; // 0x4L
+    field public static final long BT_FOLDER_TYPE_MIXED = 0L; // 0x0L
+    field public static final long BT_FOLDER_TYPE_PLAYLISTS = 5L; // 0x5L
+    field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
+    field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaDescriptionCompat!>! CREATOR;
+    field public static final String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
+    field public static final String EXTRA_DOWNLOAD_STATUS = "android.media.extra.DOWNLOAD_STATUS";
+    field public static final long STATUS_DOWNLOADED = 2L; // 0x2L
+    field public static final long STATUS_DOWNLOADING = 1L; // 0x1L
+    field public static final long STATUS_NOT_DOWNLOADED = 0L; // 0x0L
+  }
+
+  public static final class MediaDescriptionCompat.Builder {
+    ctor public MediaDescriptionCompat.Builder();
+    method public android.support.v4.media.MediaDescriptionCompat! build();
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setDescription(CharSequence?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setExtras(android.os.Bundle?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setIconBitmap(android.graphics.Bitmap?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setIconUri(android.net.Uri?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setMediaId(String?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setMediaUri(android.net.Uri?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setSubtitle(CharSequence?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setTitle(CharSequence?);
+  }
+
+  public final class MediaMetadataCompat implements android.os.Parcelable {
+    method public boolean containsKey(String!);
+    method public int describeContents();
+    method public static android.support.v4.media.MediaMetadataCompat! fromMediaMetadata(Object!);
+    method public android.graphics.Bitmap! getBitmap(String!);
+    method public android.os.Bundle! getBundle();
+    method public android.support.v4.media.MediaDescriptionCompat! getDescription();
+    method public long getLong(String!);
+    method public Object! getMediaMetadata();
+    method public android.support.v4.media.RatingCompat! getRating(String!);
+    method public String! getString(String!);
+    method public CharSequence! getText(String!);
+    method public java.util.Set<java.lang.String!>! keySet();
+    method public int size();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaMetadataCompat!>! CREATOR;
+    field public static final String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+    field public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+    field public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+    field public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+    field public static final String METADATA_KEY_ART = "android.media.metadata.ART";
+    field public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+    field public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
+    field public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+    field public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
+    field public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+    field public static final String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+    field public static final String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+    field public static final String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+    field public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+    field public static final String METADATA_KEY_DOWNLOAD_STATUS = "android.media.metadata.DOWNLOAD_STATUS";
+    field public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+    field public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+    field public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
+    field public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+    field public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
+    field public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+    field public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+    field public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+  }
+
+  public static final class MediaMetadataCompat.Builder {
+    ctor public MediaMetadataCompat.Builder();
+    ctor public MediaMetadataCompat.Builder(android.support.v4.media.MediaMetadataCompat!);
+    method public android.support.v4.media.MediaMetadataCompat! build();
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putBitmap(String!, android.graphics.Bitmap!);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putLong(String!, long);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putRating(String!, android.support.v4.media.RatingCompat!);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putString(String!, String!);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putText(String!, CharSequence!);
+  }
+
+  public final class RatingCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.RatingCompat! fromRating(Object!);
+    method public float getPercentRating();
+    method public Object! getRating();
+    method public int getRatingStyle();
+    method public float getStarRating();
+    method public boolean hasHeart();
+    method public boolean isRated();
+    method public boolean isThumbUp();
+    method public static android.support.v4.media.RatingCompat! newHeartRating(boolean);
+    method public static android.support.v4.media.RatingCompat! newPercentageRating(float);
+    method public static android.support.v4.media.RatingCompat! newStarRating(int, float);
+    method public static android.support.v4.media.RatingCompat! newThumbRating(boolean);
+    method public static android.support.v4.media.RatingCompat! newUnratedRating(int);
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.RatingCompat!>! CREATOR;
+    field public static final int RATING_3_STARS = 3; // 0x3
+    field public static final int RATING_4_STARS = 4; // 0x4
+    field public static final int RATING_5_STARS = 5; // 0x5
+    field public static final int RATING_HEART = 1; // 0x1
+    field public static final int RATING_NONE = 0; // 0x0
+    field public static final int RATING_PERCENTAGE = 6; // 0x6
+    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+  }
+
+}
+
+package android.support.v4.media.session {
+
+  public final class MediaControllerCompat {
+    ctor public MediaControllerCompat(android.content.Context!, android.support.v4.media.session.MediaSessionCompat);
+    ctor public MediaControllerCompat(android.content.Context!, android.support.v4.media.session.MediaSessionCompat.Token);
+    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat!, int);
+    method public void adjustVolume(int, int);
+    method public boolean dispatchMediaButtonEvent(android.view.KeyEvent!);
+    method public android.os.Bundle! getExtras();
+    method public long getFlags();
+    method public static android.support.v4.media.session.MediaControllerCompat! getMediaController(android.app.Activity);
+    method public Object! getMediaController();
+    method public android.support.v4.media.MediaMetadataCompat! getMetadata();
+    method public String! getPackageName();
+    method public android.support.v4.media.session.MediaControllerCompat.PlaybackInfo! getPlaybackInfo();
+    method public android.support.v4.media.session.PlaybackStateCompat! getPlaybackState();
+    method public java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! getQueue();
+    method public CharSequence! getQueueTitle();
+    method public int getRatingType();
+    method public int getRepeatMode();
+    method public android.app.PendingIntent! getSessionActivity();
+    method public android.os.Bundle getSessionInfo();
+    method public android.support.v4.media.session.MediaSessionCompat.Token! getSessionToken();
+    method public int getShuffleMode();
+    method public android.support.v4.media.session.MediaControllerCompat.TransportControls! getTransportControls();
+    method public boolean isCaptioningEnabled();
+    method public boolean isSessionReady();
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler!);
+    method public void removeQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method @Deprecated public void removeQueueItemAt(int);
+    method public void sendCommand(String, android.os.Bundle?, android.os.ResultReceiver?);
+    method public static void setMediaController(android.app.Activity, android.support.v4.media.session.MediaControllerCompat!);
+    method public void setVolumeTo(int, int);
+    method public void unregisterCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+  }
+
+  public abstract static class MediaControllerCompat.Callback implements android.os.IBinder.DeathRecipient {
+    ctor public MediaControllerCompat.Callback();
+    method public void binderDied();
+    method public void onAudioInfoChanged(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo!);
+    method public void onCaptioningEnabledChanged(boolean);
+    method public void onExtrasChanged(android.os.Bundle!);
+    method public void onMetadataChanged(android.support.v4.media.MediaMetadataCompat!);
+    method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat!);
+    method public void onQueueChanged(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>!);
+    method public void onQueueTitleChanged(CharSequence!);
+    method public void onRepeatModeChanged(int);
+    method public void onSessionDestroyed();
+    method public void onSessionEvent(String!, android.os.Bundle!);
+    method public void onSessionReady();
+    method public void onShuffleModeChanged(int);
+  }
+
+  public static final class MediaControllerCompat.PlaybackInfo {
+    method public androidx.media.AudioAttributesCompat getAudioAttributes();
+    method @Deprecated public int getAudioStream();
+    method public int getCurrentVolume();
+    method public int getMaxVolume();
+    method public int getPlaybackType();
+    method public int getVolumeControl();
+    field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
+    field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
+  }
+
+  public abstract static class MediaControllerCompat.TransportControls {
+    method public abstract void fastForward();
+    method public abstract void pause();
+    method public abstract void play();
+    method public abstract void playFromMediaId(String!, android.os.Bundle!);
+    method public abstract void playFromSearch(String!, android.os.Bundle!);
+    method public abstract void playFromUri(android.net.Uri!, android.os.Bundle!);
+    method public abstract void prepare();
+    method public abstract void prepareFromMediaId(String!, android.os.Bundle!);
+    method public abstract void prepareFromSearch(String!, android.os.Bundle!);
+    method public abstract void prepareFromUri(android.net.Uri!, android.os.Bundle!);
+    method public abstract void rewind();
+    method public abstract void seekTo(long);
+    method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction!, android.os.Bundle!);
+    method public abstract void sendCustomAction(String!, android.os.Bundle!);
+    method public abstract void setCaptioningEnabled(boolean);
+    method public void setPlaybackSpeed(float);
+    method public abstract void setRating(android.support.v4.media.RatingCompat!);
+    method public abstract void setRating(android.support.v4.media.RatingCompat!, android.os.Bundle!);
+    method public abstract void setRepeatMode(int);
+    method public abstract void setShuffleMode(int);
+    method public abstract void skipToNext();
+    method public abstract void skipToPrevious();
+    method public abstract void skipToQueueItem(long);
+    method public abstract void stop();
+    field @Deprecated public static final String EXTRA_LEGACY_STREAM_TYPE = "android.media.session.extra.LEGACY_STREAM_TYPE";
+  }
+
+  public class MediaSessionCompat {
+    ctor public MediaSessionCompat(android.content.Context, String);
+    ctor public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?);
+    ctor public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?, android.os.Bundle?);
+    method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener!);
+    method public static android.support.v4.media.session.MediaSessionCompat! fromMediaSession(android.content.Context!, Object!);
+    method public android.support.v4.media.session.MediaControllerCompat! getController();
+    method public final androidx.media.MediaSessionManager.RemoteUserInfo getCurrentControllerInfo();
+    method public Object! getMediaSession();
+    method public Object! getRemoteControlClient();
+    method public android.support.v4.media.session.MediaSessionCompat.Token! getSessionToken();
+    method public boolean isActive();
+    method public void release();
+    method public void removeOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener!);
+    method public void sendSessionEvent(String!, android.os.Bundle!);
+    method public void setActive(boolean);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback!);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback!, android.os.Handler!);
+    method public void setCaptioningEnabled(boolean);
+    method public void setExtras(android.os.Bundle!);
+    method public void setFlags(int);
+    method public void setMediaButtonReceiver(android.app.PendingIntent!);
+    method public void setMetadata(android.support.v4.media.MediaMetadataCompat!);
+    method public void setPlaybackState(android.support.v4.media.session.PlaybackStateCompat!);
+    method public void setPlaybackToLocal(int);
+    method public void setPlaybackToRemote(androidx.media.VolumeProviderCompat!);
+    method public void setQueue(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>!);
+    method public void setQueueTitle(CharSequence!);
+    method public void setRatingType(int);
+    method public void setRepeatMode(int);
+    method public void setSessionActivity(android.app.PendingIntent!);
+    method public void setShuffleMode(int);
+    field public static final String ACTION_FLAG_AS_INAPPROPRIATE = "android.support.v4.media.session.action.FLAG_AS_INAPPROPRIATE";
+    field public static final String ACTION_FOLLOW = "android.support.v4.media.session.action.FOLLOW";
+    field public static final String ACTION_SKIP_AD = "android.support.v4.media.session.action.SKIP_AD";
+    field public static final String ACTION_UNFOLLOW = "android.support.v4.media.session.action.UNFOLLOW";
+    field public static final String ARGUMENT_MEDIA_ATTRIBUTE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE";
+    field public static final String ARGUMENT_MEDIA_ATTRIBUTE_VALUE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE_VALUE";
+    field @Deprecated public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
+    field @Deprecated public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+    field public static final int MEDIA_ATTRIBUTE_ALBUM = 1; // 0x1
+    field public static final int MEDIA_ATTRIBUTE_ARTIST = 0; // 0x0
+    field public static final int MEDIA_ATTRIBUTE_PLAYLIST = 2; // 0x2
+  }
+
+  public abstract static class MediaSessionCompat.Callback {
+    ctor public MediaSessionCompat.Callback();
+    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat!, int);
+    method public void onCommand(String!, android.os.Bundle!, android.os.ResultReceiver!);
+    method public void onCustomAction(String!, android.os.Bundle!);
+    method public void onFastForward();
+    method public boolean onMediaButtonEvent(android.content.Intent!);
+    method public void onPause();
+    method public void onPlay();
+    method public void onPlayFromMediaId(String!, android.os.Bundle!);
+    method public void onPlayFromSearch(String!, android.os.Bundle!);
+    method public void onPlayFromUri(android.net.Uri!, android.os.Bundle!);
+    method public void onPrepare();
+    method public void onPrepareFromMediaId(String!, android.os.Bundle!);
+    method public void onPrepareFromSearch(String!, android.os.Bundle!);
+    method public void onPrepareFromUri(android.net.Uri!, android.os.Bundle!);
+    method public void onRemoveQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method @Deprecated public void onRemoveQueueItemAt(int);
+    method public void onRewind();
+    method public void onSeekTo(long);
+    method public void onSetCaptioningEnabled(boolean);
+    method public void onSetPlaybackSpeed(float);
+    method public void onSetRating(android.support.v4.media.RatingCompat!);
+    method public void onSetRating(android.support.v4.media.RatingCompat!, android.os.Bundle!);
+    method public void onSetRepeatMode(int);
+    method public void onSetShuffleMode(int);
+    method public void onSkipToNext();
+    method public void onSkipToPrevious();
+    method public void onSkipToQueueItem(long);
+    method public void onStop();
+  }
+
+  public static interface MediaSessionCompat.OnActiveChangeListener {
+    method public void onActiveChanged();
+  }
+
+  public static final class MediaSessionCompat.QueueItem implements android.os.Parcelable {
+    ctor public MediaSessionCompat.QueueItem(android.support.v4.media.MediaDescriptionCompat!, long);
+    method public int describeContents();
+    method public static android.support.v4.media.session.MediaSessionCompat.QueueItem! fromQueueItem(Object!);
+    method public static java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! fromQueueItemList(java.util.List<?>!);
+    method public android.support.v4.media.MediaDescriptionCompat! getDescription();
+    method public long getQueueId();
+    method public Object! getQueueItem();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! CREATOR;
+    field public static final int UNKNOWN_ID = -1; // 0xffffffff
+  }
+
+  public static final class MediaSessionCompat.Token implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.MediaSessionCompat.Token! fromToken(Object!);
+    method public Object! getToken();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.Token!>! CREATOR;
+  }
+
+  public class ParcelableVolumeInfo implements android.os.Parcelable {
+    ctor public ParcelableVolumeInfo(int, int, int, int, int);
+    ctor public ParcelableVolumeInfo(android.os.Parcel!);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.ParcelableVolumeInfo!>! CREATOR;
+    field public int audioStream;
+    field public int controlType;
+    field public int currentVolume;
+    field public int maxVolume;
+    field public int volumeType;
+  }
+
+  public final class PlaybackStateCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat! fromPlaybackState(Object!);
+    method public long getActions();
+    method public long getActiveQueueItemId();
+    method public long getBufferedPosition();
+    method public java.util.List<android.support.v4.media.session.PlaybackStateCompat.CustomAction!>! getCustomActions();
+    method public int getErrorCode();
+    method public CharSequence! getErrorMessage();
+    method public android.os.Bundle? getExtras();
+    method public long getLastPositionUpdateTime();
+    method public float getPlaybackSpeed();
+    method public Object! getPlaybackState();
+    method public long getPosition();
+    method public int getState();
+    method public static int toKeyCode(long);
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
+    field public static final long ACTION_PAUSE = 2L; // 0x2L
+    field public static final long ACTION_PLAY = 4L; // 0x4L
+    field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
+    field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+    field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
+    field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+    field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+    field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+    field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+    field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
+    field public static final long ACTION_REWIND = 8L; // 0x8L
+    field public static final long ACTION_SEEK_TO = 256L; // 0x100L
+    field public static final long ACTION_SET_CAPTIONING_ENABLED = 1048576L; // 0x100000L
+    field public static final long ACTION_SET_PLAYBACK_SPEED = 4194304L; // 0x400000L
+    field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
+    field public static final long ACTION_SET_SHUFFLE_MODE = 2097152L; // 0x200000L
+    field @Deprecated public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
+    field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
+    field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
+    field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
+    field public static final long ACTION_STOP = 1L; // 0x1L
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat!>! CREATOR;
+    field public static final int ERROR_CODE_ACTION_ABORTED = 10; // 0xa
+    field public static final int ERROR_CODE_APP_ERROR = 1; // 0x1
+    field public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; // 0x3
+    field public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; // 0x5
+    field public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; // 0x8
+    field public static final int ERROR_CODE_END_OF_QUEUE = 11; // 0xb
+    field public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; // 0x7
+    field public static final int ERROR_CODE_NOT_SUPPORTED = 2; // 0x2
+    field public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; // 0x6
+    field public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; // 0x4
+    field public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; // 0x9
+    field public static final int ERROR_CODE_UNKNOWN_ERROR = 0; // 0x0
+    field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+    field public static final int REPEAT_MODE_ALL = 2; // 0x2
+    field public static final int REPEAT_MODE_GROUP = 3; // 0x3
+    field public static final int REPEAT_MODE_INVALID = -1; // 0xffffffff
+    field public static final int REPEAT_MODE_NONE = 0; // 0x0
+    field public static final int REPEAT_MODE_ONE = 1; // 0x1
+    field public static final int SHUFFLE_MODE_ALL = 1; // 0x1
+    field public static final int SHUFFLE_MODE_GROUP = 2; // 0x2
+    field public static final int SHUFFLE_MODE_INVALID = -1; // 0xffffffff
+    field public static final int SHUFFLE_MODE_NONE = 0; // 0x0
+    field public static final int STATE_BUFFERING = 6; // 0x6
+    field public static final int STATE_CONNECTING = 8; // 0x8
+    field public static final int STATE_ERROR = 7; // 0x7
+    field public static final int STATE_FAST_FORWARDING = 4; // 0x4
+    field public static final int STATE_NONE = 0; // 0x0
+    field public static final int STATE_PAUSED = 2; // 0x2
+    field public static final int STATE_PLAYING = 3; // 0x3
+    field public static final int STATE_REWINDING = 5; // 0x5
+    field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
+    field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
+    field public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; // 0xb
+    field public static final int STATE_STOPPED = 1; // 0x1
+  }
+
+  public static final class PlaybackStateCompat.Builder {
+    ctor public PlaybackStateCompat.Builder();
+    ctor public PlaybackStateCompat.Builder(android.support.v4.media.session.PlaybackStateCompat!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! addCustomAction(String!, String!, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! addCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction!);
+    method public android.support.v4.media.session.PlaybackStateCompat! build();
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setActions(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setActiveQueueItemId(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setBufferedPosition(long);
+    method @Deprecated public android.support.v4.media.session.PlaybackStateCompat.Builder! setErrorMessage(CharSequence!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setErrorMessage(int, CharSequence!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setExtras(android.os.Bundle!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setState(int, long, float);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setState(int, long, float, long);
+  }
+
+  public static final class PlaybackStateCompat.CustomAction implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat.CustomAction! fromCustomAction(Object!);
+    method public String! getAction();
+    method public Object! getCustomAction();
+    method public android.os.Bundle! getExtras();
+    method public int getIcon();
+    method public CharSequence! getName();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat.CustomAction!>! CREATOR;
+  }
+
+  public static final class PlaybackStateCompat.CustomAction.Builder {
+    ctor public PlaybackStateCompat.CustomAction.Builder(String!, CharSequence!, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction! build();
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction.Builder! setExtras(android.os.Bundle!);
+  }
+
+}
+
+package androidx.media {
+
+  public class AudioAttributesCompat implements androidx.versionedparcelable.VersionedParcelable {
+    method public int getContentType();
+    method public int getFlags();
+    method public int getLegacyStreamType();
+    method public int getUsage();
+    method public int getVolumeControlStream();
+    method public Object? unwrap();
+    method public static androidx.media.AudioAttributesCompat? wrap(Object);
+    field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
+    field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
+    field public static final int CONTENT_TYPE_SONIFICATION = 4; // 0x4
+    field public static final int CONTENT_TYPE_SPEECH = 1; // 0x1
+    field public static final int CONTENT_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
+    field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
+    field public static final int USAGE_ALARM = 4; // 0x4
+    field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
+    field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
+    field public static final int USAGE_ASSISTANCE_SONIFICATION = 13; // 0xd
+    field public static final int USAGE_ASSISTANT = 16; // 0x10
+    field public static final int USAGE_GAME = 14; // 0xe
+    field public static final int USAGE_MEDIA = 1; // 0x1
+    field public static final int USAGE_NOTIFICATION = 5; // 0x5
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9; // 0x9
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8; // 0x8
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7; // 0x7
+    field public static final int USAGE_NOTIFICATION_EVENT = 10; // 0xa
+    field public static final int USAGE_NOTIFICATION_RINGTONE = 6; // 0x6
+    field public static final int USAGE_UNKNOWN = 0; // 0x0
+    field public static final int USAGE_VOICE_COMMUNICATION = 2; // 0x2
+    field public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3; // 0x3
+  }
+
+  public static class AudioAttributesCompat.Builder {
+    ctor public AudioAttributesCompat.Builder();
+    ctor public AudioAttributesCompat.Builder(androidx.media.AudioAttributesCompat!);
+    method public androidx.media.AudioAttributesCompat! build();
+    method public androidx.media.AudioAttributesCompat.Builder! setContentType(int);
+    method public androidx.media.AudioAttributesCompat.Builder! setFlags(int);
+    method public androidx.media.AudioAttributesCompat.Builder! setLegacyStreamType(int);
+    method public androidx.media.AudioAttributesCompat.Builder! setUsage(int);
+  }
+
+  public class AudioFocusRequestCompat {
+    method public androidx.media.AudioAttributesCompat getAudioAttributesCompat();
+    method public android.os.Handler getFocusChangeHandler();
+    method public int getFocusGain();
+    method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
+    method public boolean willPauseWhenDucked();
+  }
+
+  public static final class AudioFocusRequestCompat.Builder {
+    ctor public AudioFocusRequestCompat.Builder(int);
+    ctor public AudioFocusRequestCompat.Builder(androidx.media.AudioFocusRequestCompat);
+    method public androidx.media.AudioFocusRequestCompat! build();
+    method public androidx.media.AudioFocusRequestCompat.Builder setAudioAttributes(androidx.media.AudioAttributesCompat);
+    method public androidx.media.AudioFocusRequestCompat.Builder setFocusGain(int);
+    method public androidx.media.AudioFocusRequestCompat.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener);
+    method public androidx.media.AudioFocusRequestCompat.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
+    method public androidx.media.AudioFocusRequestCompat.Builder setWillPauseWhenDucked(boolean);
+  }
+
+  public final class AudioManagerCompat {
+    method public static int abandonAudioFocusRequest(android.media.AudioManager, androidx.media.AudioFocusRequestCompat);
+    method @IntRange(from=0) public static int getStreamMaxVolume(android.media.AudioManager, int);
+    method @IntRange(from=0) public static int getStreamMinVolume(android.media.AudioManager, int);
+    method public static boolean isVolumeFixed(android.media.AudioManager);
+    method public static int requestAudioFocus(android.media.AudioManager, androidx.media.AudioFocusRequestCompat);
+    field public static final int AUDIOFOCUS_GAIN = 1; // 0x1
+    field public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; // 0x2
+    field public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; // 0x4
+    field public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; // 0x3
+  }
+
+  public abstract class MediaBrowserServiceCompat extends android.app.Service {
+    ctor public MediaBrowserServiceCompat();
+    method public void dump(java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+    method public final android.os.Bundle! getBrowserRootHints();
+    method public final androidx.media.MediaSessionManager.RemoteUserInfo getCurrentBrowserInfo();
+    method public android.support.v4.media.session.MediaSessionCompat.Token? getSessionToken();
+    method public void notifyChildrenChanged(String);
+    method public void notifyChildrenChanged(String, android.os.Bundle);
+    method public android.os.IBinder! onBind(android.content.Intent!);
+    method public void onCustomAction(String, android.os.Bundle!, androidx.media.MediaBrowserServiceCompat.Result<android.os.Bundle!>);
+    method public abstract androidx.media.MediaBrowserServiceCompat.BrowserRoot? onGetRoot(String, int, android.os.Bundle?);
+    method public abstract void onLoadChildren(String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>);
+    method public void onLoadChildren(String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>, android.os.Bundle);
+    method public void onLoadItem(String!, androidx.media.MediaBrowserServiceCompat.Result<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+    method public void onSearch(String, android.os.Bundle!, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>);
+    method public void setSessionToken(android.support.v4.media.session.MediaSessionCompat.Token!);
+    field public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+  }
+
+  public static final class MediaBrowserServiceCompat.BrowserRoot {
+    ctor public MediaBrowserServiceCompat.BrowserRoot(String, android.os.Bundle?);
+    method public android.os.Bundle! getExtras();
+    method public String! getRootId();
+    field public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+    field public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
+    field public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+    field @Deprecated public static final String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
+  }
+
+  public static class MediaBrowserServiceCompat.Result<T> {
+    method public void detach();
+    method public void sendError(android.os.Bundle?);
+    method public void sendProgressUpdate(android.os.Bundle?);
+    method public void sendResult(T?);
+  }
+
+  public final class MediaSessionManager {
+    method public static androidx.media.MediaSessionManager getSessionManager(android.content.Context);
+    method public boolean isTrustedForMediaControl(androidx.media.MediaSessionManager.RemoteUserInfo);
+  }
+
+  public static final class MediaSessionManager.RemoteUserInfo {
+    ctor public MediaSessionManager.RemoteUserInfo(String, int, int);
+    method public String getPackageName();
+    method public int getPid();
+    method public int getUid();
+    field public static final String LEGACY_CONTROLLER = "android.media.session.MediaController";
+  }
+
+  public abstract class VolumeProviderCompat {
+    ctor public VolumeProviderCompat(int, int, int);
+    method public final int getCurrentVolume();
+    method public final int getMaxVolume();
+    method public final int getVolumeControl();
+    method public Object! getVolumeProvider();
+    method public void onAdjustVolume(int);
+    method public void onSetVolumeTo(int);
+    method public void setCallback(androidx.media.VolumeProviderCompat.Callback!);
+    method public final void setCurrentVolume(int);
+    field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+    field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+    field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
+  }
+
+  public abstract static class VolumeProviderCompat.Callback {
+    ctor public VolumeProviderCompat.Callback();
+    method public abstract void onVolumeChanged(androidx.media.VolumeProviderCompat!);
+  }
+
+}
+
+package androidx.media.app {
+
+  public class NotificationCompat {
+  }
+
+  public static class NotificationCompat.DecoratedMediaCustomViewStyle extends androidx.media.app.NotificationCompat.MediaStyle {
+    ctor public NotificationCompat.DecoratedMediaCustomViewStyle();
+  }
+
+  public static class NotificationCompat.MediaStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.MediaStyle();
+    ctor public NotificationCompat.MediaStyle(androidx.core.app.NotificationCompat.Builder!);
+    method public static android.support.v4.media.session.MediaSessionCompat.Token! getMediaSession(android.app.Notification!);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setCancelButtonIntent(android.app.PendingIntent!);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setMediaSession(android.support.v4.media.session.MediaSessionCompat.Token!);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setShowActionsInCompactView(int...);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setShowCancelButton(boolean);
+  }
+
+}
+
+package androidx.media.session {
+
+  public class MediaButtonReceiver extends android.content.BroadcastReceiver {
+    ctor public MediaButtonReceiver();
+    method public static android.app.PendingIntent! buildMediaButtonPendingIntent(android.content.Context!, long);
+    method public static android.app.PendingIntent! buildMediaButtonPendingIntent(android.content.Context!, android.content.ComponentName!, long);
+    method public static android.view.KeyEvent! handleIntent(android.support.v4.media.session.MediaSessionCompat!, android.content.Intent!);
+    method public void onReceive(android.content.Context!, android.content.Intent!);
+  }
+
+}
+
+package androidx.media.utils {
+
+  public final class MediaConstants {
+    field public static final String BROWSER_ROOT_HINTS_KEY_MEDIA_ART_SIZE_PIXELS = "android.media.extras.MEDIA_ART_SIZE_HINT_PIXELS";
+    field public static final String BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT = "androidx.media.MediaBrowserCompat.Extras.KEY_ROOT_CHILDREN_LIMIT";
+    field public static final String BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS = "androidx.media.MediaBrowserCompat.Extras.KEY_ROOT_CHILDREN_SUPPORTED_FLAGS";
+    field public static final String BROWSER_SERVICE_EXTRAS_KEY_APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT = "androidx.media.BrowserRoot.Extras.APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT";
+    field public static final String BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED = "android.media.browse.SEARCH_SUPPORTED";
+    field public static final String DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE = "androidx.media.MediaItem.Extras.COMPLETION_PERCENTAGE";
+    field public static final String DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS = "android.media.extra.PLAYBACK_STATUS";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE = "android.media.browse.CONTENT_STYLE_BROWSABLE_HINT";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE = "android.media.browse.CONTENT_STYLE_GROUP_TITLE_HINT";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE = "android.media.browse.CONTENT_STYLE_PLAYABLE_HINT";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM = "android.media.browse.CONTENT_STYLE_SINGLE_ITEM_HINT";
+    field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED = 2; // 0x2
+    field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED = 0; // 0x0
+    field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED = 1; // 0x1
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM = 4; // 0x4
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM = 3; // 0x3
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM = 2; // 0x2
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM = 1; // 0x1
+    field public static final String METADATA_KEY_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_CONTENT_ID";
+    field public static final String METADATA_KEY_IS_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+    field public static final String METADATA_KEY_IS_EXPLICIT = "android.media.IS_EXPLICIT";
+    field public static final String METADATA_KEY_NEXT_EPISODE_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_NEXT_EPISODE_CONTENT_ID";
+    field public static final String METADATA_KEY_SERIES_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_SERIES_CONTENT_ID";
+    field public static final long METADATA_VALUE_ATTRIBUTE_PRESENT = 1L; // 0x1L
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT = "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT";
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL = "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL";
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT = "androidx.media.PlaybackStateCompat.Extras.ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT";
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID = "androidx.media.PlaybackStateCompat.Extras.KEY_MEDIA_ID";
+    field public static final String SESSION_EXTRAS_KEY_ACCOUNT_NAME = "androidx.media.MediaSessionCompat.Extras.KEY_ACCOUNT_NAME";
+    field public static final String SESSION_EXTRAS_KEY_ACCOUNT_TYPE = "androidx.media.MediaSessionCompat.Extras.KEY_ACCOUNT_TYPE";
+    field public static final String SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT = "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_NEXT";
+    field public static final String SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV = "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS";
+    field public static final String TRANSPORT_CONTROLS_EXTRAS_KEY_LEGACY_STREAM_TYPE = "android.media.session.extra.LEGACY_STREAM_TYPE";
+    field public static final String TRANSPORT_CONTROLS_EXTRAS_KEY_SHUFFLE = "androidx.media.MediaControllerCompat.TransportControls.extras.KEY_SHUFFLE";
+  }
+
+}
+
diff --git a/media/media/api/res-1.6.0-beta02.txt b/media/media/api/res-1.6.0-beta02.txt
new file mode 100644
index 0000000..7a1e44d
--- /dev/null
+++ b/media/media/api/res-1.6.0-beta02.txt
@@ -0,0 +1,5 @@
+style TextAppearance_Compat_Notification_Info_Media
+style TextAppearance_Compat_Notification_Line2_Media
+style TextAppearance_Compat_Notification_Media
+style TextAppearance_Compat_Notification_Time_Media
+style TextAppearance_Compat_Notification_Title_Media
diff --git a/media/media/api/restricted_1.6.0-beta02.txt b/media/media/api/restricted_1.6.0-beta02.txt
new file mode 100644
index 0000000..ef3e28f
--- /dev/null
+++ b/media/media/api/restricted_1.6.0-beta02.txt
@@ -0,0 +1,789 @@
+// Signature format: 4.0
+package android.support.v4.media {
+
+  public final class MediaBrowserCompat {
+    ctor public MediaBrowserCompat(android.content.Context!, android.content.ComponentName!, android.support.v4.media.MediaBrowserCompat.ConnectionCallback!, android.os.Bundle!);
+    method public void connect();
+    method public void disconnect();
+    method public android.os.Bundle? getExtras();
+    method public void getItem(String, android.support.v4.media.MediaBrowserCompat.ItemCallback);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.os.Bundle? getNotifyChildrenChangedOptions();
+    method public String getRoot();
+    method public android.content.ComponentName getServiceComponent();
+    method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+    method public boolean isConnected();
+    method public void search(String, android.os.Bundle!, android.support.v4.media.MediaBrowserCompat.SearchCallback);
+    method public void sendCustomAction(String, android.os.Bundle!, android.support.v4.media.MediaBrowserCompat.CustomActionCallback?);
+    method public void subscribe(String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    method public void subscribe(String, android.os.Bundle, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    method public void unsubscribe(String);
+    method public void unsubscribe(String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+    field public static final String CUSTOM_ACTION_DOWNLOAD = "android.support.v4.media.action.DOWNLOAD";
+    field public static final String CUSTOM_ACTION_REMOVE_DOWNLOADED_FILE = "android.support.v4.media.action.REMOVE_DOWNLOADED_FILE";
+    field public static final String EXTRA_DOWNLOAD_PROGRESS = "android.media.browse.extra.DOWNLOAD_PROGRESS";
+    field public static final String EXTRA_MEDIA_ID = "android.media.browse.extra.MEDIA_ID";
+    field public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
+    field public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
+  }
+
+  public static class MediaBrowserCompat.ConnectionCallback {
+    ctor public MediaBrowserCompat.ConnectionCallback();
+    method public void onConnected();
+    method public void onConnectionFailed();
+    method public void onConnectionSuspended();
+  }
+
+  public abstract static class MediaBrowserCompat.CustomActionCallback {
+    ctor public MediaBrowserCompat.CustomActionCallback();
+    method public void onError(String!, android.os.Bundle!, android.os.Bundle!);
+    method public void onProgressUpdate(String!, android.os.Bundle!, android.os.Bundle!);
+    method public void onResult(String!, android.os.Bundle!, android.os.Bundle!);
+  }
+
+  public abstract static class MediaBrowserCompat.ItemCallback {
+    ctor public MediaBrowserCompat.ItemCallback();
+    method public void onError(String);
+    method public void onItemLoaded(android.support.v4.media.MediaBrowserCompat.MediaItem!);
+  }
+
+  public static class MediaBrowserCompat.MediaItem implements android.os.Parcelable {
+    ctor public MediaBrowserCompat.MediaItem(android.support.v4.media.MediaDescriptionCompat, int);
+    method public int describeContents();
+    method public static android.support.v4.media.MediaBrowserCompat.MediaItem! fromMediaItem(Object!);
+    method public static java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>! fromMediaItemList(java.util.List<?>!);
+    method public android.support.v4.media.MediaDescriptionCompat getDescription();
+    method public int getFlags();
+    method public String? getMediaId();
+    method public boolean isBrowsable();
+    method public boolean isPlayable();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaBrowserCompat.MediaItem!>! CREATOR;
+    field public static final int FLAG_BROWSABLE = 1; // 0x1
+    field public static final int FLAG_PLAYABLE = 2; // 0x2
+  }
+
+  public abstract static class MediaBrowserCompat.SearchCallback {
+    ctor public MediaBrowserCompat.SearchCallback();
+    method public void onError(String, android.os.Bundle!);
+    method public void onSearchResult(String, android.os.Bundle!, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+  }
+
+  public abstract static class MediaBrowserCompat.SubscriptionCallback {
+    ctor public MediaBrowserCompat.SubscriptionCallback();
+    method public void onChildrenLoaded(String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+    method public void onChildrenLoaded(String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>, android.os.Bundle);
+    method public void onError(String);
+    method public void onError(String, android.os.Bundle);
+  }
+
+  public final class MediaDescriptionCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.MediaDescriptionCompat! fromMediaDescription(Object!);
+    method public CharSequence? getDescription();
+    method public android.os.Bundle? getExtras();
+    method public android.graphics.Bitmap? getIconBitmap();
+    method public android.net.Uri? getIconUri();
+    method public Object! getMediaDescription();
+    method public String? getMediaId();
+    method public android.net.Uri? getMediaUri();
+    method public CharSequence? getSubtitle();
+    method public CharSequence? getTitle();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
+    field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
+    field public static final long BT_FOLDER_TYPE_GENRES = 4L; // 0x4L
+    field public static final long BT_FOLDER_TYPE_MIXED = 0L; // 0x0L
+    field public static final long BT_FOLDER_TYPE_PLAYLISTS = 5L; // 0x5L
+    field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
+    field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaDescriptionCompat!>! CREATOR;
+    field public static final String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
+    field public static final String EXTRA_DOWNLOAD_STATUS = "android.media.extra.DOWNLOAD_STATUS";
+    field public static final long STATUS_DOWNLOADED = 2L; // 0x2L
+    field public static final long STATUS_DOWNLOADING = 1L; // 0x1L
+    field public static final long STATUS_NOT_DOWNLOADED = 0L; // 0x0L
+  }
+
+  public static final class MediaDescriptionCompat.Builder {
+    ctor public MediaDescriptionCompat.Builder();
+    method public android.support.v4.media.MediaDescriptionCompat! build();
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setDescription(CharSequence?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setExtras(android.os.Bundle?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setIconBitmap(android.graphics.Bitmap?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setIconUri(android.net.Uri?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setMediaId(String?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setMediaUri(android.net.Uri?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setSubtitle(CharSequence?);
+    method public android.support.v4.media.MediaDescriptionCompat.Builder! setTitle(CharSequence?);
+  }
+
+  public final class MediaMetadataCompat implements android.os.Parcelable {
+    method public boolean containsKey(String!);
+    method public int describeContents();
+    method public static android.support.v4.media.MediaMetadataCompat! fromMediaMetadata(Object!);
+    method public android.graphics.Bitmap! getBitmap(String!);
+    method public android.os.Bundle! getBundle();
+    method public android.support.v4.media.MediaDescriptionCompat! getDescription();
+    method public long getLong(String!);
+    method public Object! getMediaMetadata();
+    method public android.support.v4.media.RatingCompat! getRating(String!);
+    method public String! getString(String!);
+    method public CharSequence! getText(String!);
+    method public java.util.Set<java.lang.String!>! keySet();
+    method public int size();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaMetadataCompat!>! CREATOR;
+    field public static final String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+    field public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+    field public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+    field public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+    field public static final String METADATA_KEY_ART = "android.media.metadata.ART";
+    field public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+    field public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
+    field public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+    field public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
+    field public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+    field public static final String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+    field public static final String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+    field public static final String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+    field public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+    field public static final String METADATA_KEY_DOWNLOAD_STATUS = "android.media.metadata.DOWNLOAD_STATUS";
+    field public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+    field public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+    field public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
+    field public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+    field public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
+    field public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+    field public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+    field public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+  }
+
+  public static final class MediaMetadataCompat.Builder {
+    ctor public MediaMetadataCompat.Builder();
+    ctor public MediaMetadataCompat.Builder(android.support.v4.media.MediaMetadataCompat!);
+    method public android.support.v4.media.MediaMetadataCompat! build();
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putBitmap(String!, android.graphics.Bitmap!);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putLong(String!, long);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putRating(String!, android.support.v4.media.RatingCompat!);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putString(String!, String!);
+    method public android.support.v4.media.MediaMetadataCompat.Builder! putText(String!, CharSequence!);
+  }
+
+  public final class RatingCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.RatingCompat! fromRating(Object!);
+    method public float getPercentRating();
+    method public Object! getRating();
+    method @android.support.v4.media.RatingCompat.Style public int getRatingStyle();
+    method public float getStarRating();
+    method public boolean hasHeart();
+    method public boolean isRated();
+    method public boolean isThumbUp();
+    method public static android.support.v4.media.RatingCompat! newHeartRating(boolean);
+    method public static android.support.v4.media.RatingCompat! newPercentageRating(float);
+    method public static android.support.v4.media.RatingCompat! newStarRating(int, float);
+    method public static android.support.v4.media.RatingCompat! newThumbRating(boolean);
+    method public static android.support.v4.media.RatingCompat! newUnratedRating(@android.support.v4.media.RatingCompat.Style int);
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.RatingCompat!>! CREATOR;
+    field public static final int RATING_3_STARS = 3; // 0x3
+    field public static final int RATING_4_STARS = 4; // 0x4
+    field public static final int RATING_5_STARS = 5; // 0x5
+    field public static final int RATING_HEART = 1; // 0x1
+    field public static final int RATING_NONE = 0; // 0x0
+    field public static final int RATING_PERCENTAGE = 6; // 0x6
+    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+  }
+
+  @IntDef({android.support.v4.media.RatingCompat.RATING_NONE, android.support.v4.media.RatingCompat.RATING_HEART, android.support.v4.media.RatingCompat.RATING_THUMB_UP_DOWN, android.support.v4.media.RatingCompat.RATING_3_STARS, android.support.v4.media.RatingCompat.RATING_4_STARS, android.support.v4.media.RatingCompat.RATING_5_STARS, android.support.v4.media.RatingCompat.RATING_PERCENTAGE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RatingCompat.Style {
+  }
+
+}
+
+package android.support.v4.media.session {
+
+  public final class MediaControllerCompat {
+    ctor public MediaControllerCompat(android.content.Context!, android.support.v4.media.session.MediaSessionCompat);
+    ctor public MediaControllerCompat(android.content.Context!, android.support.v4.media.session.MediaSessionCompat.Token);
+    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat!, int);
+    method public void adjustVolume(int, int);
+    method public boolean dispatchMediaButtonEvent(android.view.KeyEvent!);
+    method public android.os.Bundle! getExtras();
+    method public long getFlags();
+    method public static android.support.v4.media.session.MediaControllerCompat! getMediaController(android.app.Activity);
+    method public Object! getMediaController();
+    method public android.support.v4.media.MediaMetadataCompat! getMetadata();
+    method public String! getPackageName();
+    method public android.support.v4.media.session.MediaControllerCompat.PlaybackInfo! getPlaybackInfo();
+    method public android.support.v4.media.session.PlaybackStateCompat! getPlaybackState();
+    method public java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! getQueue();
+    method public CharSequence! getQueueTitle();
+    method public int getRatingType();
+    method public int getRepeatMode();
+    method public android.app.PendingIntent! getSessionActivity();
+    method public android.os.Bundle getSessionInfo();
+    method public android.support.v4.media.session.MediaSessionCompat.Token! getSessionToken();
+    method public int getShuffleMode();
+    method public android.support.v4.media.session.MediaControllerCompat.TransportControls! getTransportControls();
+    method public boolean isCaptioningEnabled();
+    method public boolean isSessionReady();
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+    method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler!);
+    method public void removeQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method @Deprecated public void removeQueueItemAt(int);
+    method public void sendCommand(String, android.os.Bundle?, android.os.ResultReceiver?);
+    method public static void setMediaController(android.app.Activity, android.support.v4.media.session.MediaControllerCompat!);
+    method public void setVolumeTo(int, int);
+    method public void unregisterCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+  }
+
+  public abstract static class MediaControllerCompat.Callback implements android.os.IBinder.DeathRecipient {
+    ctor public MediaControllerCompat.Callback();
+    method public void binderDied();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.support.v4.media.session.IMediaControllerCallback! getIControllerCallback();
+    method public void onAudioInfoChanged(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo!);
+    method public void onCaptioningEnabledChanged(boolean);
+    method public void onExtrasChanged(android.os.Bundle!);
+    method public void onMetadataChanged(android.support.v4.media.MediaMetadataCompat!);
+    method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat!);
+    method public void onQueueChanged(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>!);
+    method public void onQueueTitleChanged(CharSequence!);
+    method public void onRepeatModeChanged(@android.support.v4.media.session.PlaybackStateCompat.RepeatMode int);
+    method public void onSessionDestroyed();
+    method public void onSessionEvent(String!, android.os.Bundle!);
+    method public void onSessionReady();
+    method public void onShuffleModeChanged(@android.support.v4.media.session.PlaybackStateCompat.ShuffleMode int);
+  }
+
+  public static final class MediaControllerCompat.PlaybackInfo {
+    method public androidx.media.AudioAttributesCompat getAudioAttributes();
+    method @Deprecated public int getAudioStream();
+    method public int getCurrentVolume();
+    method public int getMaxVolume();
+    method public int getPlaybackType();
+    method public int getVolumeControl();
+    field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
+    field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
+  }
+
+  public abstract static class MediaControllerCompat.TransportControls {
+    method public abstract void fastForward();
+    method public abstract void pause();
+    method public abstract void play();
+    method public abstract void playFromMediaId(String!, android.os.Bundle!);
+    method public abstract void playFromSearch(String!, android.os.Bundle!);
+    method public abstract void playFromUri(android.net.Uri!, android.os.Bundle!);
+    method public abstract void prepare();
+    method public abstract void prepareFromMediaId(String!, android.os.Bundle!);
+    method public abstract void prepareFromSearch(String!, android.os.Bundle!);
+    method public abstract void prepareFromUri(android.net.Uri!, android.os.Bundle!);
+    method public abstract void rewind();
+    method public abstract void seekTo(long);
+    method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction!, android.os.Bundle!);
+    method public abstract void sendCustomAction(String!, android.os.Bundle!);
+    method public abstract void setCaptioningEnabled(boolean);
+    method public void setPlaybackSpeed(float);
+    method public abstract void setRating(android.support.v4.media.RatingCompat!);
+    method public abstract void setRating(android.support.v4.media.RatingCompat!, android.os.Bundle!);
+    method public abstract void setRepeatMode(@android.support.v4.media.session.PlaybackStateCompat.RepeatMode int);
+    method public abstract void setShuffleMode(@android.support.v4.media.session.PlaybackStateCompat.ShuffleMode int);
+    method public abstract void skipToNext();
+    method public abstract void skipToPrevious();
+    method public abstract void skipToQueueItem(long);
+    method public abstract void stop();
+    field @Deprecated public static final String EXTRA_LEGACY_STREAM_TYPE = "android.media.session.extra.LEGACY_STREAM_TYPE";
+  }
+
+  public class MediaSessionCompat {
+    ctor public MediaSessionCompat(android.content.Context, String);
+    ctor public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?);
+    ctor public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?, android.os.Bundle?);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?, android.os.Bundle?, androidx.versionedparcelable.VersionedParcelable?);
+    method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener!);
+    method public static android.support.v4.media.session.MediaSessionCompat! fromMediaSession(android.content.Context!, Object!);
+    method public android.support.v4.media.session.MediaControllerCompat! getController();
+    method public final androidx.media.MediaSessionManager.RemoteUserInfo getCurrentControllerInfo();
+    method public Object! getMediaSession();
+    method public Object! getRemoteControlClient();
+    method public android.support.v4.media.session.MediaSessionCompat.Token! getSessionToken();
+    method public boolean isActive();
+    method public void release();
+    method public void removeOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener!);
+    method public void sendSessionEvent(String!, android.os.Bundle!);
+    method public void setActive(boolean);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback!);
+    method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback!, android.os.Handler!);
+    method public void setCaptioningEnabled(boolean);
+    method public void setExtras(android.os.Bundle!);
+    method public void setFlags(int);
+    method public void setMediaButtonReceiver(android.app.PendingIntent!);
+    method public void setMetadata(android.support.v4.media.MediaMetadataCompat!);
+    method public void setPlaybackState(android.support.v4.media.session.PlaybackStateCompat!);
+    method public void setPlaybackToLocal(int);
+    method public void setPlaybackToRemote(androidx.media.VolumeProviderCompat!);
+    method public void setQueue(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>!);
+    method public void setQueueTitle(CharSequence!);
+    method public void setRatingType(@android.support.v4.media.RatingCompat.Style int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setRegistrationCallback(android.support.v4.media.session.MediaSessionCompat.RegistrationCallback?, android.os.Handler);
+    method public void setRepeatMode(@android.support.v4.media.session.PlaybackStateCompat.RepeatMode int);
+    method public void setSessionActivity(android.app.PendingIntent!);
+    method public void setShuffleMode(@android.support.v4.media.session.PlaybackStateCompat.ShuffleMode int);
+    field public static final String ACTION_FLAG_AS_INAPPROPRIATE = "android.support.v4.media.session.action.FLAG_AS_INAPPROPRIATE";
+    field public static final String ACTION_FOLLOW = "android.support.v4.media.session.action.FOLLOW";
+    field public static final String ACTION_SKIP_AD = "android.support.v4.media.session.action.SKIP_AD";
+    field public static final String ACTION_UNFOLLOW = "android.support.v4.media.session.action.UNFOLLOW";
+    field public static final String ARGUMENT_MEDIA_ATTRIBUTE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE";
+    field public static final String ARGUMENT_MEDIA_ATTRIBUTE_VALUE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE_VALUE";
+    field @Deprecated public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
+    field @Deprecated public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+    field public static final int MEDIA_ATTRIBUTE_ALBUM = 1; // 0x1
+    field public static final int MEDIA_ATTRIBUTE_ARTIST = 0; // 0x0
+    field public static final int MEDIA_ATTRIBUTE_PLAYLIST = 2; // 0x2
+  }
+
+  public abstract static class MediaSessionCompat.Callback {
+    ctor public MediaSessionCompat.Callback();
+    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat!, int);
+    method public void onCommand(String!, android.os.Bundle!, android.os.ResultReceiver!);
+    method public void onCustomAction(String!, android.os.Bundle!);
+    method public void onFastForward();
+    method public boolean onMediaButtonEvent(android.content.Intent!);
+    method public void onPause();
+    method public void onPlay();
+    method public void onPlayFromMediaId(String!, android.os.Bundle!);
+    method public void onPlayFromSearch(String!, android.os.Bundle!);
+    method public void onPlayFromUri(android.net.Uri!, android.os.Bundle!);
+    method public void onPrepare();
+    method public void onPrepareFromMediaId(String!, android.os.Bundle!);
+    method public void onPrepareFromSearch(String!, android.os.Bundle!);
+    method public void onPrepareFromUri(android.net.Uri!, android.os.Bundle!);
+    method public void onRemoveQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+    method @Deprecated public void onRemoveQueueItemAt(int);
+    method public void onRewind();
+    method public void onSeekTo(long);
+    method public void onSetCaptioningEnabled(boolean);
+    method public void onSetPlaybackSpeed(float);
+    method public void onSetRating(android.support.v4.media.RatingCompat!);
+    method public void onSetRating(android.support.v4.media.RatingCompat!, android.os.Bundle!);
+    method public void onSetRepeatMode(@android.support.v4.media.session.PlaybackStateCompat.RepeatMode int);
+    method public void onSetShuffleMode(@android.support.v4.media.session.PlaybackStateCompat.ShuffleMode int);
+    method public void onSkipToNext();
+    method public void onSkipToPrevious();
+    method public void onSkipToQueueItem(long);
+    method public void onStop();
+  }
+
+  public static interface MediaSessionCompat.OnActiveChangeListener {
+    method public void onActiveChanged();
+  }
+
+  public static final class MediaSessionCompat.QueueItem implements android.os.Parcelable {
+    ctor public MediaSessionCompat.QueueItem(android.support.v4.media.MediaDescriptionCompat!, long);
+    method public int describeContents();
+    method public static android.support.v4.media.session.MediaSessionCompat.QueueItem! fromQueueItem(Object!);
+    method public static java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! fromQueueItemList(java.util.List<?>!);
+    method public android.support.v4.media.MediaDescriptionCompat! getDescription();
+    method public long getQueueId();
+    method public Object! getQueueItem();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! CREATOR;
+    field public static final int UNKNOWN_ID = -1; // 0xffffffff
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface MediaSessionCompat.RegistrationCallback {
+    method public void onCallbackRegistered(int, int);
+    method public void onCallbackUnregistered(int, int);
+  }
+
+  public static final class MediaSessionCompat.Token implements android.os.Parcelable {
+    method public int describeContents();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.support.v4.media.session.MediaSessionCompat.Token! fromBundle(android.os.Bundle!);
+    method public static android.support.v4.media.session.MediaSessionCompat.Token! fromToken(Object!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.versionedparcelable.VersionedParcelable! getSession2Token();
+    method public Object! getToken();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSession2Token(androidx.versionedparcelable.VersionedParcelable!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.os.Bundle! toBundle();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.Token!>! CREATOR;
+  }
+
+  public class ParcelableVolumeInfo implements android.os.Parcelable {
+    ctor public ParcelableVolumeInfo(int, int, int, int, int);
+    ctor public ParcelableVolumeInfo(android.os.Parcel!);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.ParcelableVolumeInfo!>! CREATOR;
+    field public int audioStream;
+    field public int controlType;
+    field public int currentVolume;
+    field public int maxVolume;
+    field public int volumeType;
+  }
+
+  public final class PlaybackStateCompat implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat! fromPlaybackState(Object!);
+    method @android.support.v4.media.session.PlaybackStateCompat.Actions public long getActions();
+    method public long getActiveQueueItemId();
+    method public long getBufferedPosition();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public long getCurrentPosition(Long!);
+    method public java.util.List<android.support.v4.media.session.PlaybackStateCompat.CustomAction!>! getCustomActions();
+    method public int getErrorCode();
+    method public CharSequence! getErrorMessage();
+    method public android.os.Bundle? getExtras();
+    method public long getLastPositionUpdateTime();
+    method public float getPlaybackSpeed();
+    method public Object! getPlaybackState();
+    method public long getPosition();
+    method @android.support.v4.media.session.PlaybackStateCompat.State public int getState();
+    method public static int toKeyCode(long);
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
+    field public static final long ACTION_PAUSE = 2L; // 0x2L
+    field public static final long ACTION_PLAY = 4L; // 0x4L
+    field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
+    field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+    field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
+    field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+    field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+    field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+    field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+    field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
+    field public static final long ACTION_REWIND = 8L; // 0x8L
+    field public static final long ACTION_SEEK_TO = 256L; // 0x100L
+    field public static final long ACTION_SET_CAPTIONING_ENABLED = 1048576L; // 0x100000L
+    field public static final long ACTION_SET_PLAYBACK_SPEED = 4194304L; // 0x400000L
+    field public static final long ACTION_SET_RATING = 128L; // 0x80L
+    field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
+    field public static final long ACTION_SET_SHUFFLE_MODE = 2097152L; // 0x200000L
+    field @Deprecated public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
+    field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
+    field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
+    field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
+    field public static final long ACTION_STOP = 1L; // 0x1L
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat!>! CREATOR;
+    field public static final int ERROR_CODE_ACTION_ABORTED = 10; // 0xa
+    field public static final int ERROR_CODE_APP_ERROR = 1; // 0x1
+    field public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; // 0x3
+    field public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; // 0x5
+    field public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; // 0x8
+    field public static final int ERROR_CODE_END_OF_QUEUE = 11; // 0xb
+    field public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; // 0x7
+    field public static final int ERROR_CODE_NOT_SUPPORTED = 2; // 0x2
+    field public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; // 0x6
+    field public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; // 0x4
+    field public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; // 0x9
+    field public static final int ERROR_CODE_UNKNOWN_ERROR = 0; // 0x0
+    field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+    field public static final int REPEAT_MODE_ALL = 2; // 0x2
+    field public static final int REPEAT_MODE_GROUP = 3; // 0x3
+    field public static final int REPEAT_MODE_INVALID = -1; // 0xffffffff
+    field public static final int REPEAT_MODE_NONE = 0; // 0x0
+    field public static final int REPEAT_MODE_ONE = 1; // 0x1
+    field public static final int SHUFFLE_MODE_ALL = 1; // 0x1
+    field public static final int SHUFFLE_MODE_GROUP = 2; // 0x2
+    field public static final int SHUFFLE_MODE_INVALID = -1; // 0xffffffff
+    field public static final int SHUFFLE_MODE_NONE = 0; // 0x0
+    field public static final int STATE_BUFFERING = 6; // 0x6
+    field public static final int STATE_CONNECTING = 8; // 0x8
+    field public static final int STATE_ERROR = 7; // 0x7
+    field public static final int STATE_FAST_FORWARDING = 4; // 0x4
+    field public static final int STATE_NONE = 0; // 0x0
+    field public static final int STATE_PAUSED = 2; // 0x2
+    field public static final int STATE_PLAYING = 3; // 0x3
+    field public static final int STATE_REWINDING = 5; // 0x5
+    field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
+    field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
+    field public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; // 0xb
+    field public static final int STATE_STOPPED = 1; // 0x1
+  }
+
+  @LongDef(flag=true, value={android.support.v4.media.session.PlaybackStateCompat.ACTION_STOP, android.support.v4.media.session.PlaybackStateCompat.ACTION_PAUSE, android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY, android.support.v4.media.session.PlaybackStateCompat.ACTION_REWIND, android.support.v4.media.session.PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS, android.support.v4.media.session.PlaybackStateCompat.ACTION_SKIP_TO_NEXT, android.support.v4.media.session.PlaybackStateCompat.ACTION_FAST_FORWARD, android.support.v4.media.session.PlaybackStateCompat.ACTION_SET_RATING, android.support.v4.media.session.PlaybackStateCompat.ACTION_SEEK_TO, android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY_PAUSE, android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID, android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH, android.support.v4.media.session.PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM, android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY_FROM_URI, android.support.v4.media.session.PlaybackStateCompat.ACTION_PREPARE, android.support.v4.media.session.PlaybackStateCompat.ACTION_PREPARE_FROM_MEDIA_ID, android.support.v4.media.session.PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH, android.support.v4.media.session.PlaybackStateCompat.ACTION_PREPARE_FROM_URI, android.support.v4.media.session.PlaybackStateCompat.ACTION_SET_REPEAT_MODE, android.support.v4.media.session.PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE, android.support.v4.media.session.PlaybackStateCompat.ACTION_SET_CAPTIONING_ENABLED, android.support.v4.media.session.PlaybackStateCompat.ACTION_SET_PLAYBACK_SPEED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PlaybackStateCompat.Actions {
+  }
+
+  public static final class PlaybackStateCompat.Builder {
+    ctor public PlaybackStateCompat.Builder();
+    ctor public PlaybackStateCompat.Builder(android.support.v4.media.session.PlaybackStateCompat!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! addCustomAction(String!, String!, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! addCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction!);
+    method public android.support.v4.media.session.PlaybackStateCompat! build();
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setActions(@android.support.v4.media.session.PlaybackStateCompat.Actions long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setActiveQueueItemId(long);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setBufferedPosition(long);
+    method @Deprecated public android.support.v4.media.session.PlaybackStateCompat.Builder! setErrorMessage(CharSequence!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setErrorMessage(int, CharSequence!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setExtras(android.os.Bundle!);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setState(@android.support.v4.media.session.PlaybackStateCompat.State int, long, float);
+    method public android.support.v4.media.session.PlaybackStateCompat.Builder! setState(@android.support.v4.media.session.PlaybackStateCompat.State int, long, float, long);
+  }
+
+  public static final class PlaybackStateCompat.CustomAction implements android.os.Parcelable {
+    method public int describeContents();
+    method public static android.support.v4.media.session.PlaybackStateCompat.CustomAction! fromCustomAction(Object!);
+    method public String! getAction();
+    method public Object! getCustomAction();
+    method public android.os.Bundle! getExtras();
+    method public int getIcon();
+    method public CharSequence! getName();
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat.CustomAction!>! CREATOR;
+  }
+
+  public static final class PlaybackStateCompat.CustomAction.Builder {
+    ctor public PlaybackStateCompat.CustomAction.Builder(String!, CharSequence!, int);
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction! build();
+    method public android.support.v4.media.session.PlaybackStateCompat.CustomAction.Builder! setExtras(android.os.Bundle!);
+  }
+
+  @IntDef({android.support.v4.media.session.PlaybackStateCompat.REPEAT_MODE_INVALID, android.support.v4.media.session.PlaybackStateCompat.REPEAT_MODE_NONE, android.support.v4.media.session.PlaybackStateCompat.REPEAT_MODE_ONE, android.support.v4.media.session.PlaybackStateCompat.REPEAT_MODE_ALL, android.support.v4.media.session.PlaybackStateCompat.REPEAT_MODE_GROUP}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PlaybackStateCompat.RepeatMode {
+  }
+
+  @IntDef({android.support.v4.media.session.PlaybackStateCompat.SHUFFLE_MODE_INVALID, android.support.v4.media.session.PlaybackStateCompat.SHUFFLE_MODE_NONE, android.support.v4.media.session.PlaybackStateCompat.SHUFFLE_MODE_ALL, android.support.v4.media.session.PlaybackStateCompat.SHUFFLE_MODE_GROUP}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PlaybackStateCompat.ShuffleMode {
+  }
+
+  @IntDef({android.support.v4.media.session.PlaybackStateCompat.STATE_NONE, android.support.v4.media.session.PlaybackStateCompat.STATE_STOPPED, android.support.v4.media.session.PlaybackStateCompat.STATE_PAUSED, android.support.v4.media.session.PlaybackStateCompat.STATE_PLAYING, android.support.v4.media.session.PlaybackStateCompat.STATE_FAST_FORWARDING, android.support.v4.media.session.PlaybackStateCompat.STATE_REWINDING, android.support.v4.media.session.PlaybackStateCompat.STATE_BUFFERING, android.support.v4.media.session.PlaybackStateCompat.STATE_ERROR, android.support.v4.media.session.PlaybackStateCompat.STATE_CONNECTING, android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_PREVIOUS, android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_NEXT, android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PlaybackStateCompat.State {
+  }
+
+}
+
+package androidx.media {
+
+  @androidx.versionedparcelable.VersionedParcelize(jetifyAs="android.support.v4.media.AudioAttributesCompat") public class AudioAttributesCompat implements androidx.versionedparcelable.VersionedParcelable {
+    method public int getContentType();
+    method public int getFlags();
+    method public int getLegacyStreamType();
+    method public int getUsage();
+    method public int getVolumeControlStream();
+    method public Object? unwrap();
+    method public static androidx.media.AudioAttributesCompat? wrap(Object);
+    field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
+    field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
+    field public static final int CONTENT_TYPE_SONIFICATION = 4; // 0x4
+    field public static final int CONTENT_TYPE_SPEECH = 1; // 0x1
+    field public static final int CONTENT_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
+    field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
+    field public static final int USAGE_ALARM = 4; // 0x4
+    field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
+    field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
+    field public static final int USAGE_ASSISTANCE_SONIFICATION = 13; // 0xd
+    field public static final int USAGE_ASSISTANT = 16; // 0x10
+    field public static final int USAGE_GAME = 14; // 0xe
+    field public static final int USAGE_MEDIA = 1; // 0x1
+    field public static final int USAGE_NOTIFICATION = 5; // 0x5
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9; // 0x9
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8; // 0x8
+    field public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7; // 0x7
+    field public static final int USAGE_NOTIFICATION_EVENT = 10; // 0xa
+    field public static final int USAGE_NOTIFICATION_RINGTONE = 6; // 0x6
+    field public static final int USAGE_UNKNOWN = 0; // 0x0
+    field public static final int USAGE_VOICE_COMMUNICATION = 2; // 0x2
+    field public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3; // 0x3
+  }
+
+  public static class AudioAttributesCompat.Builder {
+    ctor public AudioAttributesCompat.Builder();
+    ctor public AudioAttributesCompat.Builder(androidx.media.AudioAttributesCompat!);
+    method public androidx.media.AudioAttributesCompat! build();
+    method public androidx.media.AudioAttributesCompat.Builder! setContentType(int);
+    method public androidx.media.AudioAttributesCompat.Builder! setFlags(int);
+    method public androidx.media.AudioAttributesCompat.Builder! setLegacyStreamType(int);
+    method public androidx.media.AudioAttributesCompat.Builder! setUsage(int);
+  }
+
+  public class AudioFocusRequestCompat {
+    method public androidx.media.AudioAttributesCompat getAudioAttributesCompat();
+    method public android.os.Handler getFocusChangeHandler();
+    method public int getFocusGain();
+    method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
+    method public boolean willPauseWhenDucked();
+  }
+
+  public static final class AudioFocusRequestCompat.Builder {
+    ctor public AudioFocusRequestCompat.Builder(int);
+    ctor public AudioFocusRequestCompat.Builder(androidx.media.AudioFocusRequestCompat);
+    method public androidx.media.AudioFocusRequestCompat! build();
+    method public androidx.media.AudioFocusRequestCompat.Builder setAudioAttributes(androidx.media.AudioAttributesCompat);
+    method public androidx.media.AudioFocusRequestCompat.Builder setFocusGain(int);
+    method public androidx.media.AudioFocusRequestCompat.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener);
+    method public androidx.media.AudioFocusRequestCompat.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
+    method public androidx.media.AudioFocusRequestCompat.Builder setWillPauseWhenDucked(boolean);
+  }
+
+  public final class AudioManagerCompat {
+    method public static int abandonAudioFocusRequest(android.media.AudioManager, androidx.media.AudioFocusRequestCompat);
+    method @IntRange(from=0) public static int getStreamMaxVolume(android.media.AudioManager, @androidx.core.app.NotificationCompat.StreamType int);
+    method @IntRange(from=0) public static int getStreamMinVolume(android.media.AudioManager, @androidx.core.app.NotificationCompat.StreamType int);
+    method public static boolean isVolumeFixed(android.media.AudioManager);
+    method public static int requestAudioFocus(android.media.AudioManager, androidx.media.AudioFocusRequestCompat);
+    field public static final int AUDIOFOCUS_GAIN = 1; // 0x1
+    field public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; // 0x2
+    field public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; // 0x4
+    field public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; // 0x3
+  }
+
+  public abstract class MediaBrowserServiceCompat extends android.app.Service {
+    ctor public MediaBrowserServiceCompat();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void attachToBaseContext(android.content.Context!);
+    method public void dump(java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+    method public final android.os.Bundle! getBrowserRootHints();
+    method public final androidx.media.MediaSessionManager.RemoteUserInfo getCurrentBrowserInfo();
+    method public android.support.v4.media.session.MediaSessionCompat.Token? getSessionToken();
+    method public void notifyChildrenChanged(String);
+    method public void notifyChildrenChanged(String, android.os.Bundle);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void notifyChildrenChanged(androidx.media.MediaSessionManager.RemoteUserInfo, String, android.os.Bundle);
+    method public android.os.IBinder! onBind(android.content.Intent!);
+    method public void onCustomAction(String, android.os.Bundle!, androidx.media.MediaBrowserServiceCompat.Result<android.os.Bundle!>);
+    method public abstract androidx.media.MediaBrowserServiceCompat.BrowserRoot? onGetRoot(String, int, android.os.Bundle?);
+    method public abstract void onLoadChildren(String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>);
+    method public void onLoadChildren(String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>, android.os.Bundle);
+    method public void onLoadItem(String!, androidx.media.MediaBrowserServiceCompat.Result<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+    method public void onSearch(String, android.os.Bundle!, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>);
+    method public void setSessionToken(android.support.v4.media.session.MediaSessionCompat.Token!);
+    field public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+  }
+
+  public static final class MediaBrowserServiceCompat.BrowserRoot {
+    ctor public MediaBrowserServiceCompat.BrowserRoot(String, android.os.Bundle?);
+    method public android.os.Bundle! getExtras();
+    method public String! getRootId();
+    field public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+    field public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
+    field public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+    field @Deprecated public static final String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
+  }
+
+  public static class MediaBrowserServiceCompat.Result<T> {
+    method public void detach();
+    method public void sendError(android.os.Bundle?);
+    method public void sendProgressUpdate(android.os.Bundle?);
+    method public void sendResult(T?);
+  }
+
+  public final class MediaSessionManager {
+    method public static androidx.media.MediaSessionManager getSessionManager(android.content.Context);
+    method public boolean isTrustedForMediaControl(androidx.media.MediaSessionManager.RemoteUserInfo);
+  }
+
+  public static final class MediaSessionManager.RemoteUserInfo {
+    ctor public MediaSessionManager.RemoteUserInfo(String, int, int);
+    method public String getPackageName();
+    method public int getPid();
+    method public int getUid();
+    field public static final String LEGACY_CONTROLLER = "android.media.session.MediaController";
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int UNKNOWN_PID = -1; // 0xffffffff
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int UNKNOWN_UID = -1; // 0xffffffff
+  }
+
+  public abstract class VolumeProviderCompat {
+    ctor public VolumeProviderCompat(@androidx.media.VolumeProviderCompat.ControlType int, int, int);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public VolumeProviderCompat(@androidx.media.VolumeProviderCompat.ControlType int, int, int, String?);
+    method public final int getCurrentVolume();
+    method public final int getMaxVolume();
+    method @androidx.media.VolumeProviderCompat.ControlType public final int getVolumeControl();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final String? getVolumeControlId();
+    method public Object! getVolumeProvider();
+    method public void onAdjustVolume(int);
+    method public void onSetVolumeTo(int);
+    method public void setCallback(androidx.media.VolumeProviderCompat.Callback!);
+    method public final void setCurrentVolume(int);
+    field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+    field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+    field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
+  }
+
+  public abstract static class VolumeProviderCompat.Callback {
+    ctor public VolumeProviderCompat.Callback();
+    method public abstract void onVolumeChanged(androidx.media.VolumeProviderCompat!);
+  }
+
+  @IntDef({androidx.media.VolumeProviderCompat.VOLUME_CONTROL_FIXED, androidx.media.VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, androidx.media.VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface VolumeProviderCompat.ControlType {
+  }
+
+}
+
+package androidx.media.app {
+
+  public class NotificationCompat {
+  }
+
+  public static class NotificationCompat.DecoratedMediaCustomViewStyle extends androidx.media.app.NotificationCompat.MediaStyle {
+    ctor public NotificationCompat.DecoratedMediaCustomViewStyle();
+  }
+
+  public static class NotificationCompat.MediaStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.MediaStyle();
+    ctor public NotificationCompat.MediaStyle(androidx.core.app.NotificationCompat.Builder!);
+    method public static android.support.v4.media.session.MediaSessionCompat.Token! getMediaSession(android.app.Notification!);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setCancelButtonIntent(android.app.PendingIntent!);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setMediaSession(android.support.v4.media.session.MediaSessionCompat.Token!);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setShowActionsInCompactView(int...);
+    method public androidx.media.app.NotificationCompat.MediaStyle! setShowCancelButton(boolean);
+  }
+
+}
+
+package androidx.media.session {
+
+  public class MediaButtonReceiver extends android.content.BroadcastReceiver {
+    ctor public MediaButtonReceiver();
+    method public static android.app.PendingIntent! buildMediaButtonPendingIntent(android.content.Context!, long);
+    method public static android.app.PendingIntent! buildMediaButtonPendingIntent(android.content.Context!, android.content.ComponentName!, long);
+    method public static android.view.KeyEvent! handleIntent(android.support.v4.media.session.MediaSessionCompat!, android.content.Intent!);
+    method public void onReceive(android.content.Context!, android.content.Intent!);
+  }
+
+}
+
+package androidx.media.utils {
+
+  public final class MediaConstants {
+    field public static final String BROWSER_ROOT_HINTS_KEY_MEDIA_ART_SIZE_PIXELS = "android.media.extras.MEDIA_ART_SIZE_HINT_PIXELS";
+    field public static final String BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT = "androidx.media.MediaBrowserCompat.Extras.KEY_ROOT_CHILDREN_LIMIT";
+    field public static final String BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS = "androidx.media.MediaBrowserCompat.Extras.KEY_ROOT_CHILDREN_SUPPORTED_FLAGS";
+    field public static final String BROWSER_SERVICE_EXTRAS_KEY_APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT = "androidx.media.BrowserRoot.Extras.APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT";
+    field public static final String BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED = "android.media.browse.SEARCH_SUPPORTED";
+    field public static final String DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE = "androidx.media.MediaItem.Extras.COMPLETION_PERCENTAGE";
+    field public static final String DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS = "android.media.extra.PLAYBACK_STATUS";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE = "android.media.browse.CONTENT_STYLE_BROWSABLE_HINT";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE = "android.media.browse.CONTENT_STYLE_GROUP_TITLE_HINT";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE = "android.media.browse.CONTENT_STYLE_PLAYABLE_HINT";
+    field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM = "android.media.browse.CONTENT_STYLE_SINGLE_ITEM_HINT";
+    field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED = 2; // 0x2
+    field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED = 0; // 0x0
+    field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED = 1; // 0x1
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM = 4; // 0x4
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM = 3; // 0x3
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM = 2; // 0x2
+    field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM = 1; // 0x1
+    field public static final String METADATA_KEY_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_CONTENT_ID";
+    field public static final String METADATA_KEY_IS_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+    field public static final String METADATA_KEY_IS_EXPLICIT = "android.media.IS_EXPLICIT";
+    field public static final String METADATA_KEY_NEXT_EPISODE_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_NEXT_EPISODE_CONTENT_ID";
+    field public static final String METADATA_KEY_SERIES_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_SERIES_CONTENT_ID";
+    field public static final long METADATA_VALUE_ATTRIBUTE_PRESENT = 1L; // 0x1L
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT = "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT";
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL = "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL";
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT = "androidx.media.PlaybackStateCompat.Extras.ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT";
+    field public static final String PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID = "androidx.media.PlaybackStateCompat.Extras.KEY_MEDIA_ID";
+    field public static final String SESSION_EXTRAS_KEY_ACCOUNT_NAME = "androidx.media.MediaSessionCompat.Extras.KEY_ACCOUNT_NAME";
+    field public static final String SESSION_EXTRAS_KEY_ACCOUNT_TYPE = "androidx.media.MediaSessionCompat.Extras.KEY_ACCOUNT_TYPE";
+    field public static final String SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT = "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_NEXT";
+    field public static final String SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV = "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS";
+    field public static final String TRANSPORT_CONTROLS_EXTRAS_KEY_LEGACY_STREAM_TYPE = "android.media.session.extra.LEGACY_STREAM_TYPE";
+    field public static final String TRANSPORT_CONTROLS_EXTRAS_KEY_SHUFFLE = "androidx.media.MediaControllerCompat.TransportControls.extras.KEY_SHUFFLE";
+  }
+
+}
+
diff --git a/room/room-migration/api/restricted_current.txt b/room/room-migration/api/restricted_current.txt
index 90348c9..8d5b5f4 100644
--- a/room/room-migration/api/restricted_current.txt
+++ b/room/room-migration/api/restricted_current.txt
@@ -17,12 +17,14 @@
     method public String getIdentityHash();
     method public int getVersion();
     method public java.util.List<androidx.room.migration.bundle.DatabaseViewBundle> getViews();
+    method public final java.util.Map<java.lang.String,androidx.room.migration.bundle.DatabaseViewBundle> getViewsByName();
     method public boolean isSchemaEqual(androidx.room.migration.bundle.DatabaseBundle other);
     property public java.util.List<androidx.room.migration.bundle.EntityBundle> entities;
     property public java.util.Map<java.lang.String,androidx.room.migration.bundle.EntityBundle> entitiesByTableName;
     property public String identityHash;
     property public int version;
     property public java.util.List<androidx.room.migration.bundle.DatabaseViewBundle> views;
+    property public final java.util.Map<java.lang.String,androidx.room.migration.bundle.DatabaseViewBundle> viewsByName;
   }
 
   public static final class DatabaseBundle.FtsEntityCreateComparator implements java.util.Comparator<androidx.room.migration.bundle.EntityBundle> {
diff --git a/room/room-migration/src/main/java/androidx/room/migration/bundle/DatabaseBundle.kt b/room/room-migration/src/main/java/androidx/room/migration/bundle/DatabaseBundle.kt
index dc0e86c..73534e3 100644
--- a/room/room-migration/src/main/java/androidx/room/migration/bundle/DatabaseBundle.kt
+++ b/room/room-migration/src/main/java/androidx/room/migration/bundle/DatabaseBundle.kt
@@ -56,6 +56,11 @@
         entities.associateBy { it.tableName }
     }
 
+    @delegate:Transient
+    public val viewsByName: Map<String, DatabaseViewBundle> by lazy {
+        views.associateBy { it.viewName }
+    }
+
     /**
      * @return List of SQL queries to build this database from scratch.
      */
@@ -73,10 +78,8 @@
 
     @Override
     override fun isSchemaEqual(other: DatabaseBundle): Boolean {
-        return checkSchemaEquality(
-            entitiesByTableName,
-            other.entitiesByTableName
-        )
+        return checkSchemaEquality(entitiesByTableName, other.entitiesByTableName) &&
+            checkSchemaEquality(viewsByName, other.viewsByName)
     }
 
     // Comparator to sort FTS entities after their declared external content entity so that the
diff --git a/room/room-migration/src/test/java/androidx/room/migration/bundle/DatabaseBundleTest.kt b/room/room-migration/src/test/java/androidx/room/migration/bundle/DatabaseBundleTest.kt
index 8da656e..7726687 100644
--- a/room/room-migration/src/test/java/androidx/room/migration/bundle/DatabaseBundleTest.kt
+++ b/room/room-migration/src/test/java/androidx/room/migration/bundle/DatabaseBundleTest.kt
@@ -98,6 +98,23 @@
         assertThat(bundle.buildCreateQueries(), `is`(listOf("sq1", "sq3", "sq2", "e2_trig")))
     }
 
+    @Test
+    fun schemaEquality_missingView_notEqual() {
+        val entity = EntityBundle("e", "sq",
+            listOf(createFieldBundle("foo"), createFieldBundle("bar")),
+            PrimaryKeyBundle(false, listOf("foo")),
+            emptyList(),
+            emptyList())
+        val view = DatabaseViewBundle("bar", "sq")
+        val bundle1 = DatabaseBundle(1, "hash",
+            listOf(entity), emptyList(),
+            emptyList())
+        val bundle2 = DatabaseBundle(1, "hash",
+            listOf(entity), listOf(view),
+            emptyList())
+        assertThat(bundle1.isSchemaEqual(bundle2), `is`(false))
+    }
+
     private fun createFieldBundle(name: String): FieldBundle {
         return FieldBundle("foo", name, "text", false, null)
     }
diff --git a/room/room-runtime-lint/src/main/java/androidx/room/lint/CursorKotlinUseIssueDetector.kt b/room/room-runtime-lint/src/main/java/androidx/room/lint/CursorKotlinUseIssueDetector.kt
index 97e69b0..4ddc81c 100644
--- a/room/room-runtime-lint/src/main/java/androidx/room/lint/CursorKotlinUseIssueDetector.kt
+++ b/room/room-runtime-lint/src/main/java/androidx/room/lint/CursorKotlinUseIssueDetector.kt
@@ -27,6 +27,7 @@
 import com.android.tools.lint.detector.api.Scope
 import com.android.tools.lint.detector.api.Severity
 import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.android.tools.lint.detector.api.VersionChecks
 import com.android.tools.lint.detector.api.minSdkLessThan
 import com.intellij.psi.PsiMethod
 import org.jetbrains.uast.UCallExpression
@@ -63,8 +64,8 @@
         }
         // If the call is within an SDK_INT check, then its OK
         if (
-            isWithinVersionCheckConditional(context, node, 16) ||
-            isPrecededByVersionCheckExit(context, node, 16)
+            VersionChecks.isWithinVersionCheckConditional(context, node, 16) ||
+            VersionChecks.isPrecededByVersionCheckExit(context, node, 16)
         ) {
             return
         }
diff --git a/temp/sample/optin/bar/package-info.class b/temp/sample/optin/bar/package-info.class
new file mode 100644
index 0000000..cdb1f10
--- /dev/null
+++ b/temp/sample/optin/bar/package-info.class
Binary files differ
diff --git a/wear/compose/compose-material/api/current.txt b/wear/compose/compose-material/api/current.txt
index f31cbcc8..a9a68e1 100644
--- a/wear/compose/compose-material/api/current.txt
+++ b/wear/compose/compose-material/api/current.txt
@@ -201,6 +201,7 @@
   }
 
   public final class PickerDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.gestures.FlingBehavior flingBehavior(androidx.wear.compose.material.PickerState state, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float> decay);
     method public float getDefaultGradientRatio();
     method public androidx.wear.compose.material.ScalingParams scalingParams(optional float edgeScale, optional float edgeAlpha, optional float minElementHeight, optional float maxElementHeight, optional float minTransitionArea, optional float maxTransitionArea, optional androidx.compose.animation.core.Easing scaleInterpolator, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.Constraints,java.lang.Integer> viewportVerticalOffsetResolver);
     property public final float DefaultGradientRatio;
@@ -208,7 +209,7 @@
   }
 
   public final class PickerKt {
-    method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+    method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
     method @androidx.compose.runtime.Composable public static androidx.wear.compose.material.PickerState rememberPickerState(int initialNumberOfOptions, optional int initiallySelectedOption, optional boolean repeatItems);
   }
 
@@ -217,13 +218,17 @@
     property public abstract int selectedOption;
   }
 
-  @androidx.compose.runtime.Stable public final class PickerState {
+  @androidx.compose.runtime.Stable public final class PickerState implements androidx.compose.foundation.gestures.ScrollableState {
     ctor public PickerState(int initialNumberOfOptions, optional int initiallySelectedOption, optional boolean repeatItems);
+    method public float dispatchRawDelta(float delta);
     method public int getNumberOfOptions();
     method public boolean getRepeatItems();
     method public int getSelectedOption();
+    method public boolean isScrollInProgress();
+    method public suspend Object? scroll(androidx.compose.foundation.MutatePriority scrollPriority, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.gestures.ScrollScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public suspend Object? scrollToOption(int index, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public void setNumberOfOptions(int newNumberOfOptions);
+    property public boolean isScrollInProgress;
     property public final int numberOfOptions;
     property public final boolean repeatItems;
     property public final int selectedOption;
@@ -329,7 +334,7 @@
     property public final int ItemStart;
   }
 
-  public interface ScalingLazyListItemInfo {
+  public sealed interface ScalingLazyListItemInfo {
     method public float getAlpha();
     method public int getIndex();
     method public Object getKey();
@@ -348,13 +353,13 @@
     property public abstract int unadjustedSize;
   }
 
-  @androidx.compose.runtime.Stable @androidx.wear.compose.material.ScalingLazyScopeMarker public interface ScalingLazyListItemScope {
+  @androidx.compose.runtime.Stable @androidx.wear.compose.material.ScalingLazyScopeMarker public sealed interface ScalingLazyListItemScope {
     method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional float fraction);
     method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional float fraction);
     method public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional float fraction);
   }
 
-  public interface ScalingLazyListLayoutInfo {
+  public sealed interface ScalingLazyListLayoutInfo {
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -371,7 +376,7 @@
     property public abstract java.util.List<androidx.wear.compose.material.ScalingLazyListItemInfo> visibleItemsInfo;
   }
 
-  @androidx.wear.compose.material.ScalingLazyScopeMarker public interface ScalingLazyListScope {
+  @androidx.wear.compose.material.ScalingLazyScopeMarker public sealed interface ScalingLazyListScope {
     method public void item(optional Object? key, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListItemScope,kotlin.Unit> content);
     method public void items(int count, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super java.lang.Integer,kotlin.Unit> itemContent);
   }
diff --git a/wear/compose/compose-material/api/public_plus_experimental_current.txt b/wear/compose/compose-material/api/public_plus_experimental_current.txt
index d008a6f..afd54bd 100644
--- a/wear/compose/compose-material/api/public_plus_experimental_current.txt
+++ b/wear/compose/compose-material/api/public_plus_experimental_current.txt
@@ -216,6 +216,7 @@
   }
 
   public final class PickerDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.gestures.FlingBehavior flingBehavior(androidx.wear.compose.material.PickerState state, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float> decay);
     method public float getDefaultGradientRatio();
     method public androidx.wear.compose.material.ScalingParams scalingParams(optional float edgeScale, optional float edgeAlpha, optional float minElementHeight, optional float maxElementHeight, optional float minTransitionArea, optional float maxTransitionArea, optional androidx.compose.animation.core.Easing scaleInterpolator, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.Constraints,java.lang.Integer> viewportVerticalOffsetResolver);
     property public final float DefaultGradientRatio;
@@ -223,7 +224,7 @@
   }
 
   public final class PickerKt {
-    method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+    method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
     method @androidx.compose.runtime.Composable public static androidx.wear.compose.material.PickerState rememberPickerState(int initialNumberOfOptions, optional int initiallySelectedOption, optional boolean repeatItems);
   }
 
@@ -232,13 +233,17 @@
     property public abstract int selectedOption;
   }
 
-  @androidx.compose.runtime.Stable public final class PickerState {
+  @androidx.compose.runtime.Stable public final class PickerState implements androidx.compose.foundation.gestures.ScrollableState {
     ctor public PickerState(int initialNumberOfOptions, optional int initiallySelectedOption, optional boolean repeatItems);
+    method public float dispatchRawDelta(float delta);
     method public int getNumberOfOptions();
     method public boolean getRepeatItems();
     method public int getSelectedOption();
+    method public boolean isScrollInProgress();
+    method public suspend Object? scroll(androidx.compose.foundation.MutatePriority scrollPriority, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.gestures.ScrollScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public suspend Object? scrollToOption(int index, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public void setNumberOfOptions(int newNumberOfOptions);
+    property public boolean isScrollInProgress;
     property public final int numberOfOptions;
     property public final boolean repeatItems;
     property public final int selectedOption;
@@ -355,7 +360,7 @@
     property public final int ItemStart;
   }
 
-  public interface ScalingLazyListItemInfo {
+  public sealed interface ScalingLazyListItemInfo {
     method public float getAlpha();
     method public int getIndex();
     method public Object getKey();
@@ -374,13 +379,13 @@
     property public abstract int unadjustedSize;
   }
 
-  @androidx.compose.runtime.Stable @androidx.wear.compose.material.ScalingLazyScopeMarker public interface ScalingLazyListItemScope {
+  @androidx.compose.runtime.Stable @androidx.wear.compose.material.ScalingLazyScopeMarker public sealed interface ScalingLazyListItemScope {
     method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional float fraction);
     method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional float fraction);
     method public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional float fraction);
   }
 
-  public interface ScalingLazyListLayoutInfo {
+  public sealed interface ScalingLazyListLayoutInfo {
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -397,7 +402,7 @@
     property public abstract java.util.List<androidx.wear.compose.material.ScalingLazyListItemInfo> visibleItemsInfo;
   }
 
-  @androidx.wear.compose.material.ScalingLazyScopeMarker public interface ScalingLazyListScope {
+  @androidx.wear.compose.material.ScalingLazyScopeMarker public sealed interface ScalingLazyListScope {
     method public void item(optional Object? key, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListItemScope,kotlin.Unit> content);
     method public void items(int count, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super java.lang.Integer,kotlin.Unit> itemContent);
   }
diff --git a/wear/compose/compose-material/api/restricted_current.txt b/wear/compose/compose-material/api/restricted_current.txt
index f31cbcc8..a9a68e1 100644
--- a/wear/compose/compose-material/api/restricted_current.txt
+++ b/wear/compose/compose-material/api/restricted_current.txt
@@ -201,6 +201,7 @@
   }
 
   public final class PickerDefaults {
+    method @androidx.compose.runtime.Composable public androidx.compose.foundation.gestures.FlingBehavior flingBehavior(androidx.wear.compose.material.PickerState state, optional androidx.compose.animation.core.DecayAnimationSpec<java.lang.Float> decay);
     method public float getDefaultGradientRatio();
     method public androidx.wear.compose.material.ScalingParams scalingParams(optional float edgeScale, optional float edgeAlpha, optional float minElementHeight, optional float maxElementHeight, optional float minTransitionArea, optional float maxTransitionArea, optional androidx.compose.animation.core.Easing scaleInterpolator, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.unit.Constraints,java.lang.Integer> viewportVerticalOffsetResolver);
     property public final float DefaultGradientRatio;
@@ -208,7 +209,7 @@
   }
 
   public final class PickerKt {
-    method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+    method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
     method @androidx.compose.runtime.Composable public static androidx.wear.compose.material.PickerState rememberPickerState(int initialNumberOfOptions, optional int initiallySelectedOption, optional boolean repeatItems);
   }
 
@@ -217,13 +218,17 @@
     property public abstract int selectedOption;
   }
 
-  @androidx.compose.runtime.Stable public final class PickerState {
+  @androidx.compose.runtime.Stable public final class PickerState implements androidx.compose.foundation.gestures.ScrollableState {
     ctor public PickerState(int initialNumberOfOptions, optional int initiallySelectedOption, optional boolean repeatItems);
+    method public float dispatchRawDelta(float delta);
     method public int getNumberOfOptions();
     method public boolean getRepeatItems();
     method public int getSelectedOption();
+    method public boolean isScrollInProgress();
+    method public suspend Object? scroll(androidx.compose.foundation.MutatePriority scrollPriority, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.gestures.ScrollScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public suspend Object? scrollToOption(int index, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
     method public void setNumberOfOptions(int newNumberOfOptions);
+    property public boolean isScrollInProgress;
     property public final int numberOfOptions;
     property public final boolean repeatItems;
     property public final int selectedOption;
@@ -329,7 +334,7 @@
     property public final int ItemStart;
   }
 
-  public interface ScalingLazyListItemInfo {
+  public sealed interface ScalingLazyListItemInfo {
     method public float getAlpha();
     method public int getIndex();
     method public Object getKey();
@@ -348,13 +353,13 @@
     property public abstract int unadjustedSize;
   }
 
-  @androidx.compose.runtime.Stable @androidx.wear.compose.material.ScalingLazyScopeMarker public interface ScalingLazyListItemScope {
+  @androidx.compose.runtime.Stable @androidx.wear.compose.material.ScalingLazyScopeMarker public sealed interface ScalingLazyListItemScope {
     method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional float fraction);
     method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional float fraction);
     method public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional float fraction);
   }
 
-  public interface ScalingLazyListLayoutInfo {
+  public sealed interface ScalingLazyListLayoutInfo {
     method public androidx.compose.foundation.gestures.Orientation getOrientation();
     method public boolean getReverseLayout();
     method public int getTotalItemsCount();
@@ -371,7 +376,7 @@
     property public abstract java.util.List<androidx.wear.compose.material.ScalingLazyListItemInfo> visibleItemsInfo;
   }
 
-  @androidx.wear.compose.material.ScalingLazyScopeMarker public interface ScalingLazyListScope {
+  @androidx.wear.compose.material.ScalingLazyScopeMarker public sealed interface ScalingLazyListScope {
     method public void item(optional Object? key, kotlin.jvm.functions.Function1<? super androidx.wear.compose.material.ScalingLazyListItemScope,kotlin.Unit> content);
     method public void items(int count, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,?>? key, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.ScalingLazyListItemScope,? super java.lang.Integer,kotlin.Unit> itemContent);
   }
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Picker.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Picker.kt
index 9160c1f..dfb8887 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Picker.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/Picker.kt
@@ -17,7 +17,13 @@
 package androidx.wear.compose.material
 
 import androidx.compose.animation.core.CubicBezierEasing
+import androidx.compose.animation.core.DecayAnimationSpec
 import androidx.compose.animation.core.Easing
+import androidx.compose.animation.core.exponentialDecay
+import androidx.compose.foundation.MutatePriority
+import androidx.compose.foundation.gestures.FlingBehavior
+import androidx.compose.foundation.gestures.ScrollScope
+import androidx.compose.foundation.gestures.ScrollableState
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
@@ -70,6 +76,7 @@
  * so the top 1/3 and the bottom 1/3 of the picker are taken by gradients. Should be between 0.0 and
  * 0.5. Use 0.0 to disable the gradient.
  * @param gradientColor Should be the color outside of the Picker, so there is continuity.
+ * @param flingBehavior logic describing fling behavior.
  * @param option A block which describes the content. Inside this block you can reference
  * [PickerScope.selectedOption] and other properties in [PickerScope]. When read-only mode is in
  * use on a screen, it is recommended that this content is given [Alignment.Center] in order to
@@ -86,6 +93,7 @@
     /* @FloatRange(from = 0.0, to = 0.5) */
     gradientRatio: Float = PickerDefaults.DefaultGradientRatio,
     gradientColor: Color = MaterialTheme.colors.background,
+    flingBehavior: FlingBehavior = PickerDefaults.flingBehavior(state),
     option: @Composable PickerScope.(optionIndex: Int) -> Unit
 ) {
     require(gradientRatio in 0f..0.5f) { "gradientRatio should be between 0.0 and 0.5" }
@@ -133,7 +141,7 @@
             verticalArrangement = Arrangement.spacedBy(
                 space = separation
             ),
-            flingBehavior = ScalingLazyColumnDefaults.snapFlingBehavior(state.scalingLazyListState)
+            flingBehavior = flingBehavior
         )
     }
 
@@ -179,7 +187,7 @@
     initialNumberOfOptions: Int,
     initiallySelectedOption: Int = 0,
     val repeatItems: Boolean = true
-) {
+) : ScrollableState {
     init {
         require(initialNumberOfOptions > 0) { "The picker should have at least one item." }
     }
@@ -258,6 +266,20 @@
             }
         )
     }
+
+    override suspend fun scroll(
+        scrollPriority: MutatePriority,
+        block: suspend ScrollScope.() -> Unit
+    ) {
+        scalingLazyListState.scroll(scrollPriority, block)
+    }
+
+    override fun dispatchRawDelta(delta: Float): Float {
+        return scalingLazyListState.dispatchRawDelta(delta)
+    }
+
+    override val isScrollInProgress: Boolean
+        get() = scalingLazyListState.isScrollInProgress
 }
 
 /**
@@ -288,6 +310,27 @@
         viewportVerticalOffsetResolver = viewportVerticalOffsetResolver
     )
 
+    /**
+     * Create and remember a [FlingBehavior] that will represent natural fling curve with snap to
+     * central item as the fling decays.
+     *
+     * @param state the state of the [Picker]
+     * @param decay the decay to use
+     */
+    @Composable
+    public fun flingBehavior(
+        state: PickerState,
+        decay: DecayAnimationSpec<Float> = exponentialDecay()
+    ): FlingBehavior {
+        return remember(state, decay) {
+            ScalingLazyColumnSnapFlingBehavior(
+                state = state.scalingLazyListState,
+                snapOffset = 0,
+                decay = decay
+            )
+        }
+    }
+
     val DefaultGradientRatio = 0.33f
 }
 
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/PositionIndicator.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/PositionIndicator.kt
index 0fa2540..fd96ef0 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/PositionIndicator.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/PositionIndicator.kt
@@ -233,8 +233,8 @@
 
         // TODO(b/224770222): Add tests.
         /**
-         * Position the indicator opposite to the physical rsb. (at the left for default mode and
-         * at the right if the device is rotated 180 degrees)
+         * Position the indicator opposite to the physical rotating side button (RSB). (at the left
+         * by default and at the right if the device is rotated 180 degrees)
          * This is the default for RSB indicators as we want to avoid it being obscured when the
          * user is interacting with the RSB.
          */
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
index fd0d20f..e53cd95 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyColumn.kt
@@ -61,7 +61,7 @@
  * Receiver scope which is used by [ScalingLazyColumn].
  */
 @ScalingLazyScopeMarker
-public interface ScalingLazyListScope {
+public sealed interface ScalingLazyListScope {
     /**
      * Adds a single item.
      *
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListItemInfo.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListItemInfo.kt
index 8a59f84..b80fb6a 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListItemInfo.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListItemInfo.kt
@@ -20,7 +20,7 @@
  *
  * @see ScalingLazyListLayoutInfo
  */
-interface ScalingLazyListItemInfo {
+public sealed interface ScalingLazyListItemInfo {
     /**
      * The index of the item in the list.
      */
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListItemScope.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListItemScope.kt
index c28add0..bb00507 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListItemScope.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListItemScope.kt
@@ -29,7 +29,7 @@
  */
 @Stable
 @ScalingLazyScopeMarker
-interface ScalingLazyListItemScope {
+public sealed interface ScalingLazyListItemScope {
     /**
      * Have the content fill the [Constraints.maxWidth] and [Constraints.maxHeight] of the parent
      * measurement constraints by setting the [minimum width][Constraints.minWidth] to be equal to
diff --git a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfo.kt b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfo.kt
index 02d3c62..dfbf945 100644
--- a/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfo.kt
+++ b/wear/compose/compose-material/src/commonMain/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfo.kt
@@ -24,7 +24,7 @@
  *
  * Use [ScalingLazyListState.layoutInfo] to retrieve this
  */
-interface ScalingLazyListLayoutInfo {
+public sealed interface ScalingLazyListLayoutInfo {
     /**
      * The list of [ScalingLazyListItemInfo] representing all the currently visible items.
      */
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt
index 91bd2eb..fdeaf94 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/DemoApp.kt
@@ -197,22 +197,18 @@
 fun Modifier.rsbScroll(
     scrollableState: ScrollableState,
     flingBehavior: FlingBehavior,
+    focusRequester: FocusRequester
 ): Modifier {
     val channel = remember { Channel<TimestampedDelta>(
         capacity = 10,
         onBufferOverflow = BufferOverflow.DROP_OLDEST
     ) }
-    val focusRequester = remember { FocusRequester() }
 
     var lastTimeMillis = remember { 0L }
     var smoothSpeed = remember { 0f }
     val speedWindowMillis = 200L
     val timeoutToFling = 100L
 
-    LaunchedEffect(Unit) {
-        focusRequester.requestFocus()
-    }
-
     return composed {
         var rsbScrollInProgress by remember { mutableStateOf(false) }
         LaunchedEffect(rsbScrollInProgress) {
@@ -279,8 +275,13 @@
     val flingBehavior = if (snap) ScalingLazyColumnDefaults.snapFlingBehavior(
         state = state
     ) else ScrollableDefaults.flingBehavior()
+    val focusRequester = remember { FocusRequester() }
     ScalingLazyColumn(
-        modifier = modifier.rsbScroll(scrollableState = state, flingBehavior = flingBehavior),
+        modifier = modifier.rsbScroll(
+            scrollableState = state,
+            flingBehavior = flingBehavior,
+            focusRequester = focusRequester
+        ),
         state = state,
         reverseLayout = reverseLayout,
         scalingParams = scalingParams,
@@ -289,4 +290,7 @@
         verticalArrangement = verticalArrangement,
         content = content
     )
+    LaunchedEffect(Unit) {
+        focusRequester.requestFocus()
+    }
 }
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt
index f90990a..8a0ad6b 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PickerDemo.kt
@@ -17,6 +17,7 @@
 package androidx.wear.compose.integration.demos
 
 import android.view.MotionEvent
+import androidx.compose.foundation.gestures.FlingBehavior
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
@@ -42,6 +43,7 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.input.pointer.pointerInteropFilter
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.res.painterResource
@@ -55,6 +57,8 @@
 import androidx.wear.compose.material.Icon
 import androidx.wear.compose.material.MaterialTheme
 import androidx.wear.compose.material.Picker
+import androidx.wear.compose.material.PickerDefaults
+import androidx.wear.compose.material.PickerScope
 import androidx.wear.compose.material.PickerState
 import androidx.wear.compose.material.Text
 import androidx.wear.compose.material.rememberPickerState
@@ -74,6 +78,9 @@
         var selectedColumn by remember { mutableStateOf(0) }
         val textStyle = MaterialTheme.typography.display3
         val optionColor = MaterialTheme.colors.secondary
+        val focusRequester1 = remember { FocusRequester() }
+        val focusRequester2 = remember { FocusRequester() }
+        val focusRequester3 = remember { FocusRequester() }
         Box(modifier = Modifier.fillMaxSize()) {
             Column(
                 verticalArrangement = Arrangement.Center,
@@ -97,14 +104,14 @@
                     verticalAlignment = Alignment.CenterVertically,
                     horizontalArrangement = Arrangement.Center,
                 ) {
-                    val pickerModifier = Modifier.size(40.dp, 100.dp)
-                    Picker(
+                    PickerWithRSB(
                         readOnly = selectedColumn != 0,
                         state = rememberPickerState(
                             initialNumberOfOptions = 24,
                             initiallySelectedOption = 6
                         ),
-                        modifier = pickerModifier,
+                        focusRequester = focusRequester1,
+                        modifier = Modifier.size(40.dp, 100.dp),
                     ) { hour: Int ->
                         TimePiece(
                             selected = selectedColumn == 0,
@@ -114,10 +121,11 @@
                         )
                     }
                     Separator(6.dp, textStyle)
-                    Picker(
+                    PickerWithRSB(
                         readOnly = selectedColumn != 1,
                         state = rememberPickerState(initialNumberOfOptions = 60),
-                        modifier = pickerModifier,
+                        focusRequester = focusRequester2,
+                        modifier = Modifier.size(40.dp, 100.dp),
                     ) { minute: Int ->
                         TimePiece(
                             selected = selectedColumn == 1,
@@ -127,10 +135,11 @@
                         )
                     }
                     Separator(6.dp, textStyle)
-                    Picker(
+                    PickerWithRSB(
                         readOnly = selectedColumn != 2,
                         state = rememberPickerState(initialNumberOfOptions = 60),
-                        modifier = pickerModifier,
+                        focusRequester = focusRequester3,
+                        modifier = Modifier.size(40.dp, 100.dp),
                     ) { second: Int ->
                         TimePiece(
                             selected = selectedColumn == 2,
@@ -150,6 +159,10 @@
                 }
                 Spacer(Modifier.height(12.dp))
             }
+            LaunchedEffect(selectedColumn) {
+                listOf(focusRequester1, focusRequester2, focusRequester3)[selectedColumn]
+                    .requestFocus()
+            }
         }
     }
 }
@@ -167,6 +180,9 @@
         var morning by remember { mutableStateOf(true) }
         var selectedColumn by remember { mutableStateOf(0) }
         val textStyle = MaterialTheme.typography.display1
+        val focusRequester1 = remember { FocusRequester() }
+        val focusRequester2 = remember { FocusRequester() }
+
         Column(
             modifier = Modifier.fillMaxSize(),
             verticalArrangement = Arrangement.Center,
@@ -198,13 +214,14 @@
                 horizontalArrangement = Arrangement.Center,
             ) {
                 Spacer(Modifier.width(8.dp))
-                Picker(
+                PickerWithRSB(
                     readOnly = selectedColumn != 0,
                     state = rememberPickerState(
                         initialNumberOfOptions = 12,
                         initiallySelectedOption = 6
                     ),
-                    modifier = Modifier.size(64.dp, 100.dp),
+                    focusRequester = focusRequester1,
+                    modifier = Modifier.size(40.dp, 100.dp),
                     readOnlyLabel = { LabelText("Hour") }
                 ) { hour: Int ->
                     TimePiece(
@@ -215,9 +232,11 @@
                     )
                 }
                 Separator(8.dp, textStyle)
-                Picker(
+
+                PickerWithRSB(
                     readOnly = selectedColumn != 1,
                     state = rememberPickerState(initialNumberOfOptions = 60),
+                    focusRequester = focusRequester2,
                     modifier = Modifier.size(64.dp, 100.dp),
                     readOnlyLabel = { LabelText("Min") }
                 ) { minute: Int ->
@@ -239,6 +258,9 @@
                 )
             }
             Spacer(Modifier.height(8.dp))
+            LaunchedEffect(selectedColumn) {
+                listOf(focusRequester1, focusRequester2)[selectedColumn].requestFocus()
+            }
         }
     }
 }
@@ -272,6 +294,10 @@
             initialNumberOfOptions = maxDayInMonth,
             initiallySelectedOption = today.get(Calendar.DAY_OF_MONTH) - 1
         )
+        val focusRequester1 = remember { FocusRequester() }
+        val focusRequester2 = remember { FocusRequester() }
+        val focusRequester3 = remember { FocusRequester() }
+
         LaunchedEffect(maxDayInMonth) {
             if (maxDayInMonth != dayState.numberOfOptions) {
                 dayState.numberOfOptions = maxDayInMonth
@@ -324,7 +350,8 @@
                             readOnly = selectedColumn != 0,
                             onSelected = { selectedColumn = 0 },
                             text = { day: Int -> "%d".format(day + 1) },
-                            width = dayWidth
+                            width = dayWidth,
+                            focusRequester = focusRequester1
                         )
                         Spacer(modifier = Modifier.width(spacerWidth))
                     }
@@ -333,7 +360,8 @@
                         readOnly = selectedColumn != 1,
                         onSelected = { selectedColumn = 1 },
                         text = { month: Int -> monthNames[month] },
-                        width = monthWidth
+                        width = monthWidth,
+                        focusRequester = focusRequester2
                     )
                     if (selectedColumn > 0) {
                         Spacer(modifier = Modifier.width(spacerWidth))
@@ -342,7 +370,8 @@
                             readOnly = selectedColumn != 2,
                             onSelected = { selectedColumn = 2 },
                             text = { year: Int -> "%4d".format(year + 1) },
-                            width = yearWidth
+                            width = yearWidth,
+                            focusRequester = focusRequester3
                         )
                     }
                 }
@@ -361,6 +390,10 @@
                 }
                 Spacer(Modifier.height(12.dp))
             }
+            LaunchedEffect(selectedColumn) {
+                listOf(focusRequester1, focusRequester2, focusRequester3)[selectedColumn]
+                    .requestFocus()
+            }
         }
     }
 }
@@ -371,11 +404,13 @@
     readOnly: Boolean,
     onSelected: () -> Unit,
     text: (option: Int) -> String,
+    focusRequester: FocusRequester,
     width: Dp
 ) {
-    Picker(
+    PickerWithRSB(
         readOnly = readOnly,
         state = state,
+        focusRequester = focusRequester,
         modifier = Modifier.size(width, 100.dp),
     ) { option ->
         TimePiece(
@@ -433,4 +468,27 @@
         color = MaterialTheme.colors.onBackground
     )
     Spacer(Modifier.width(width))
-}
\ No newline at end of file
+}
+
+@Composable fun PickerWithRSB(
+    state: PickerState,
+    readOnly: Boolean,
+    modifier: Modifier,
+    focusRequester: FocusRequester,
+    readOnlyLabel: @Composable (BoxScope.() -> Unit)? = null,
+    flingBehavior: FlingBehavior = PickerDefaults.flingBehavior(state = state),
+    option: @Composable PickerScope.(optionIndex: Int) -> Unit
+) {
+    Picker(
+        state = state,
+        modifier = modifier.rsbScroll(
+            scrollableState = state,
+            flingBehavior = flingBehavior,
+            focusRequester = focusRequester
+        ),
+        flingBehavior = flingBehavior,
+        readOnly = readOnly,
+        readOnlyLabel = readOnlyLabel,
+        option = option
+    )
+}
diff --git a/wear/tiles/tiles-material/api/current.txt b/wear/tiles/tiles-material/api/current.txt
index a8ed27f..5962e2f 100644
--- a/wear/tiles/tiles-material/api/current.txt
+++ b/wear/tiles/tiles-material/api/current.txt
@@ -5,7 +5,7 @@
     method public androidx.wear.tiles.material.ButtonColors getButtonColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
+    method public CharSequence getContentDescription();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getSize();
   }
 
@@ -14,7 +14,7 @@
     method public androidx.wear.tiles.material.Button build();
     method public androidx.wear.tiles.material.Button.Builder setButtonColors(androidx.wear.tiles.material.ButtonColors);
     method public androidx.wear.tiles.material.Button.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.Button.Builder setContentDescription(String);
+    method public androidx.wear.tiles.material.Button.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.Button.Builder setIconContent(String, androidx.wear.tiles.DimensionBuilders.DpProp);
     method public androidx.wear.tiles.material.Button.Builder setIconContent(String);
     method public androidx.wear.tiles.material.Button.Builder setImageContent(String);
@@ -45,7 +45,7 @@
     method public androidx.wear.tiles.material.ChipColors getChipColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
+    method public CharSequence getContentDescription();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
     method public int getHorizontalAlignment();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
@@ -56,13 +56,13 @@
     method public androidx.wear.tiles.material.Chip build();
     method public androidx.wear.tiles.material.Chip.Builder setChipColors(androidx.wear.tiles.material.ChipColors);
     method public androidx.wear.tiles.material.Chip.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.Chip.Builder setContentDescription(String);
+    method public androidx.wear.tiles.material.Chip.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.Chip.Builder setHorizontalAlignment(int);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextContent(String);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextIconContent(String, String);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextLabelContent(String, String);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextLabelIconContent(String, String, String);
-    method public androidx.wear.tiles.material.Chip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.DpProp);
+    method public androidx.wear.tiles.material.Chip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.ContainerDimension);
     method public androidx.wear.tiles.material.Chip.Builder setWidth(@Dimension(unit=androidx.annotation.Dimension.DP) float);
   }
 
@@ -78,19 +78,10 @@
   }
 
   public class ChipDefaults {
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp COMPACT_HEIGHT;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp COMPACT_HORIZONTAL_PADDING;
     field public static final androidx.wear.tiles.material.ChipColors COMPACT_PRIMARY;
     field public static final androidx.wear.tiles.material.ChipColors COMPACT_SECONDARY;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_HEIGHT;
-    field public static final float DEFAULT_MARGIN_PERCENT = 5.2f;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp HORIZONTAL_PADDING;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp ICON_SIZE;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp ICON_SPACER_WIDTH;
     field public static final androidx.wear.tiles.material.ChipColors PRIMARY;
     field public static final androidx.wear.tiles.material.ChipColors SECONDARY;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp TITLE_HEIGHT;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp TITLE_HORIZONTAL_PADDING;
     field public static final androidx.wear.tiles.material.ChipColors TITLE_PRIMARY;
     field public static final androidx.wear.tiles.material.ChipColors TITLE_SECONDARY;
   }
@@ -108,7 +99,7 @@
     ctor public CircularProgressIndicator.Builder();
     method public androidx.wear.tiles.material.CircularProgressIndicator build();
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setCircularProgressIndicatorColors(androidx.wear.tiles.material.ProgressIndicatorColors);
-    method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setContentDescription(String);
+    method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setEndAngle(float);
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setProgress(@FloatRange(from=0, to=1) float);
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setStartAngle(float);
@@ -120,9 +111,6 @@
     method public androidx.wear.tiles.material.ChipColors getChipColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
-    method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
-    method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
   }
 
   public static final class CompactChip.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
@@ -140,7 +128,6 @@
 
   public class ProgressIndicatorDefaults {
     field public static final androidx.wear.tiles.material.ProgressIndicatorColors DEFAULT_COLOR;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_PADDING;
     field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_STROKE_WIDTH;
     field public static final float GAP_END_ANGLE = 156.1f;
     field public static final float GAP_START_ANGLE = -156.1f;
@@ -177,8 +164,6 @@
     method public androidx.wear.tiles.material.ChipColors getChipColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
-    method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
     method public int getHorizontalAlignment();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
   }
@@ -188,7 +173,7 @@
     method public androidx.wear.tiles.material.TitleChip build();
     method public androidx.wear.tiles.material.TitleChip.Builder setChipColors(androidx.wear.tiles.material.ChipColors);
     method public androidx.wear.tiles.material.TitleChip.Builder setHorizontalAlignment(int);
-    method public androidx.wear.tiles.material.TitleChip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.DpProp);
+    method public androidx.wear.tiles.material.TitleChip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.ContainerDimension);
     method public androidx.wear.tiles.material.TitleChip.Builder setWidth(@Dimension(unit=androidx.annotation.Dimension.DP) float);
   }
 
@@ -219,12 +204,6 @@
   }
 
   public class MultiSlotLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout toLayout();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout.Builder toLayoutBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline toTimeline();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline.Builder toTimelineBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry toTimelineEntry();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder toTimelineEntryBuilder();
   }
 
   public static final class MultiSlotLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
@@ -239,12 +218,6 @@
   }
 
   public class PrimaryLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout toLayout();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout.Builder toLayoutBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline toTimeline();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline.Builder toTimelineBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry toTimelineEntry();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder toTimelineEntryBuilder();
   }
 
   public static final class PrimaryLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
@@ -259,12 +232,6 @@
 
   public class ProgressIndicatorLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout toLayout();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout.Builder toLayoutBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline toTimeline();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline.Builder toTimelineBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry toTimelineEntry();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder toTimelineEntryBuilder();
   }
 
   public static final class ProgressIndicatorLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
diff --git a/wear/tiles/tiles-material/api/public_plus_experimental_current.txt b/wear/tiles/tiles-material/api/public_plus_experimental_current.txt
index a8ed27f..5962e2f 100644
--- a/wear/tiles/tiles-material/api/public_plus_experimental_current.txt
+++ b/wear/tiles/tiles-material/api/public_plus_experimental_current.txt
@@ -5,7 +5,7 @@
     method public androidx.wear.tiles.material.ButtonColors getButtonColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
+    method public CharSequence getContentDescription();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getSize();
   }
 
@@ -14,7 +14,7 @@
     method public androidx.wear.tiles.material.Button build();
     method public androidx.wear.tiles.material.Button.Builder setButtonColors(androidx.wear.tiles.material.ButtonColors);
     method public androidx.wear.tiles.material.Button.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.Button.Builder setContentDescription(String);
+    method public androidx.wear.tiles.material.Button.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.Button.Builder setIconContent(String, androidx.wear.tiles.DimensionBuilders.DpProp);
     method public androidx.wear.tiles.material.Button.Builder setIconContent(String);
     method public androidx.wear.tiles.material.Button.Builder setImageContent(String);
@@ -45,7 +45,7 @@
     method public androidx.wear.tiles.material.ChipColors getChipColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
+    method public CharSequence getContentDescription();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
     method public int getHorizontalAlignment();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
@@ -56,13 +56,13 @@
     method public androidx.wear.tiles.material.Chip build();
     method public androidx.wear.tiles.material.Chip.Builder setChipColors(androidx.wear.tiles.material.ChipColors);
     method public androidx.wear.tiles.material.Chip.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.Chip.Builder setContentDescription(String);
+    method public androidx.wear.tiles.material.Chip.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.Chip.Builder setHorizontalAlignment(int);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextContent(String);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextIconContent(String, String);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextLabelContent(String, String);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextLabelIconContent(String, String, String);
-    method public androidx.wear.tiles.material.Chip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.DpProp);
+    method public androidx.wear.tiles.material.Chip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.ContainerDimension);
     method public androidx.wear.tiles.material.Chip.Builder setWidth(@Dimension(unit=androidx.annotation.Dimension.DP) float);
   }
 
@@ -78,19 +78,10 @@
   }
 
   public class ChipDefaults {
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp COMPACT_HEIGHT;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp COMPACT_HORIZONTAL_PADDING;
     field public static final androidx.wear.tiles.material.ChipColors COMPACT_PRIMARY;
     field public static final androidx.wear.tiles.material.ChipColors COMPACT_SECONDARY;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_HEIGHT;
-    field public static final float DEFAULT_MARGIN_PERCENT = 5.2f;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp HORIZONTAL_PADDING;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp ICON_SIZE;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp ICON_SPACER_WIDTH;
     field public static final androidx.wear.tiles.material.ChipColors PRIMARY;
     field public static final androidx.wear.tiles.material.ChipColors SECONDARY;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp TITLE_HEIGHT;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp TITLE_HORIZONTAL_PADDING;
     field public static final androidx.wear.tiles.material.ChipColors TITLE_PRIMARY;
     field public static final androidx.wear.tiles.material.ChipColors TITLE_SECONDARY;
   }
@@ -108,7 +99,7 @@
     ctor public CircularProgressIndicator.Builder();
     method public androidx.wear.tiles.material.CircularProgressIndicator build();
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setCircularProgressIndicatorColors(androidx.wear.tiles.material.ProgressIndicatorColors);
-    method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setContentDescription(String);
+    method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setEndAngle(float);
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setProgress(@FloatRange(from=0, to=1) float);
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setStartAngle(float);
@@ -120,9 +111,6 @@
     method public androidx.wear.tiles.material.ChipColors getChipColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
-    method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
-    method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
   }
 
   public static final class CompactChip.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
@@ -140,7 +128,6 @@
 
   public class ProgressIndicatorDefaults {
     field public static final androidx.wear.tiles.material.ProgressIndicatorColors DEFAULT_COLOR;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_PADDING;
     field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_STROKE_WIDTH;
     field public static final float GAP_END_ANGLE = 156.1f;
     field public static final float GAP_START_ANGLE = -156.1f;
@@ -177,8 +164,6 @@
     method public androidx.wear.tiles.material.ChipColors getChipColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
-    method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
     method public int getHorizontalAlignment();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
   }
@@ -188,7 +173,7 @@
     method public androidx.wear.tiles.material.TitleChip build();
     method public androidx.wear.tiles.material.TitleChip.Builder setChipColors(androidx.wear.tiles.material.ChipColors);
     method public androidx.wear.tiles.material.TitleChip.Builder setHorizontalAlignment(int);
-    method public androidx.wear.tiles.material.TitleChip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.DpProp);
+    method public androidx.wear.tiles.material.TitleChip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.ContainerDimension);
     method public androidx.wear.tiles.material.TitleChip.Builder setWidth(@Dimension(unit=androidx.annotation.Dimension.DP) float);
   }
 
@@ -219,12 +204,6 @@
   }
 
   public class MultiSlotLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout toLayout();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout.Builder toLayoutBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline toTimeline();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline.Builder toTimelineBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry toTimelineEntry();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder toTimelineEntryBuilder();
   }
 
   public static final class MultiSlotLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
@@ -239,12 +218,6 @@
   }
 
   public class PrimaryLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout toLayout();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout.Builder toLayoutBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline toTimeline();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline.Builder toTimelineBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry toTimelineEntry();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder toTimelineEntryBuilder();
   }
 
   public static final class PrimaryLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
@@ -259,12 +232,6 @@
 
   public class ProgressIndicatorLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout toLayout();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout.Builder toLayoutBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline toTimeline();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline.Builder toTimelineBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry toTimelineEntry();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder toTimelineEntryBuilder();
   }
 
   public static final class ProgressIndicatorLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
diff --git a/wear/tiles/tiles-material/api/restricted_current.txt b/wear/tiles/tiles-material/api/restricted_current.txt
index a8ed27f..5962e2f 100644
--- a/wear/tiles/tiles-material/api/restricted_current.txt
+++ b/wear/tiles/tiles-material/api/restricted_current.txt
@@ -5,7 +5,7 @@
     method public androidx.wear.tiles.material.ButtonColors getButtonColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
+    method public CharSequence getContentDescription();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getSize();
   }
 
@@ -14,7 +14,7 @@
     method public androidx.wear.tiles.material.Button build();
     method public androidx.wear.tiles.material.Button.Builder setButtonColors(androidx.wear.tiles.material.ButtonColors);
     method public androidx.wear.tiles.material.Button.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.Button.Builder setContentDescription(String);
+    method public androidx.wear.tiles.material.Button.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.Button.Builder setIconContent(String, androidx.wear.tiles.DimensionBuilders.DpProp);
     method public androidx.wear.tiles.material.Button.Builder setIconContent(String);
     method public androidx.wear.tiles.material.Button.Builder setImageContent(String);
@@ -45,7 +45,7 @@
     method public androidx.wear.tiles.material.ChipColors getChipColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
+    method public CharSequence getContentDescription();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
     method public int getHorizontalAlignment();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
@@ -56,13 +56,13 @@
     method public androidx.wear.tiles.material.Chip build();
     method public androidx.wear.tiles.material.Chip.Builder setChipColors(androidx.wear.tiles.material.ChipColors);
     method public androidx.wear.tiles.material.Chip.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.Chip.Builder setContentDescription(String);
+    method public androidx.wear.tiles.material.Chip.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.Chip.Builder setHorizontalAlignment(int);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextContent(String);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextIconContent(String, String);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextLabelContent(String, String);
     method public androidx.wear.tiles.material.Chip.Builder setPrimaryTextLabelIconContent(String, String, String);
-    method public androidx.wear.tiles.material.Chip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.DpProp);
+    method public androidx.wear.tiles.material.Chip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.ContainerDimension);
     method public androidx.wear.tiles.material.Chip.Builder setWidth(@Dimension(unit=androidx.annotation.Dimension.DP) float);
   }
 
@@ -78,19 +78,10 @@
   }
 
   public class ChipDefaults {
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp COMPACT_HEIGHT;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp COMPACT_HORIZONTAL_PADDING;
     field public static final androidx.wear.tiles.material.ChipColors COMPACT_PRIMARY;
     field public static final androidx.wear.tiles.material.ChipColors COMPACT_SECONDARY;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_HEIGHT;
-    field public static final float DEFAULT_MARGIN_PERCENT = 5.2f;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp HORIZONTAL_PADDING;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp ICON_SIZE;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp ICON_SPACER_WIDTH;
     field public static final androidx.wear.tiles.material.ChipColors PRIMARY;
     field public static final androidx.wear.tiles.material.ChipColors SECONDARY;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp TITLE_HEIGHT;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp TITLE_HORIZONTAL_PADDING;
     field public static final androidx.wear.tiles.material.ChipColors TITLE_PRIMARY;
     field public static final androidx.wear.tiles.material.ChipColors TITLE_SECONDARY;
   }
@@ -108,7 +99,7 @@
     ctor public CircularProgressIndicator.Builder();
     method public androidx.wear.tiles.material.CircularProgressIndicator build();
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setCircularProgressIndicatorColors(androidx.wear.tiles.material.ProgressIndicatorColors);
-    method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setContentDescription(String);
+    method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setEndAngle(float);
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setProgress(@FloatRange(from=0, to=1) float);
     method public androidx.wear.tiles.material.CircularProgressIndicator.Builder setStartAngle(float);
@@ -120,9 +111,6 @@
     method public androidx.wear.tiles.material.ChipColors getChipColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
-    method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
-    method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
   }
 
   public static final class CompactChip.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
@@ -140,7 +128,6 @@
 
   public class ProgressIndicatorDefaults {
     field public static final androidx.wear.tiles.material.ProgressIndicatorColors DEFAULT_COLOR;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_PADDING;
     field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_STROKE_WIDTH;
     field public static final float GAP_END_ANGLE = 156.1f;
     field public static final float GAP_START_ANGLE = -156.1f;
@@ -177,8 +164,6 @@
     method public androidx.wear.tiles.material.ChipColors getChipColors();
     method public androidx.wear.tiles.ModifiersBuilders.Clickable getClickable();
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public String getContentDescription();
-    method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
     method public int getHorizontalAlignment();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
   }
@@ -188,7 +173,7 @@
     method public androidx.wear.tiles.material.TitleChip build();
     method public androidx.wear.tiles.material.TitleChip.Builder setChipColors(androidx.wear.tiles.material.ChipColors);
     method public androidx.wear.tiles.material.TitleChip.Builder setHorizontalAlignment(int);
-    method public androidx.wear.tiles.material.TitleChip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.DpProp);
+    method public androidx.wear.tiles.material.TitleChip.Builder setWidth(androidx.wear.tiles.DimensionBuilders.ContainerDimension);
     method public androidx.wear.tiles.material.TitleChip.Builder setWidth(@Dimension(unit=androidx.annotation.Dimension.DP) float);
   }
 
@@ -219,12 +204,6 @@
   }
 
   public class MultiSlotLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout toLayout();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout.Builder toLayoutBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline toTimeline();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline.Builder toTimelineBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry toTimelineEntry();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder toTimelineEntryBuilder();
   }
 
   public static final class MultiSlotLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
@@ -239,12 +218,6 @@
   }
 
   public class PrimaryLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout toLayout();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout.Builder toLayoutBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline toTimeline();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline.Builder toTimelineBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry toTimelineEntry();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder toTimelineEntryBuilder();
   }
 
   public static final class PrimaryLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
@@ -259,12 +232,6 @@
 
   public class ProgressIndicatorLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement getContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout toLayout();
-    method public androidx.wear.tiles.LayoutElementBuilders.Layout.Builder toLayoutBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline toTimeline();
-    method public androidx.wear.tiles.TimelineBuilders.Timeline.Builder toTimelineBuilder();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry toTimelineEntry();
-    method public androidx.wear.tiles.TimelineBuilders.TimelineEntry.Builder toTimelineEntryBuilder();
   }
 
   public static final class ProgressIndicatorLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Button.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Button.java
index 487fbc8..2bc518c 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Button.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Button.java
@@ -87,7 +87,7 @@
         @NonNull private final Context mContext;
         @Nullable private LayoutElement mCustomContent;
         @NonNull private final Clickable mClickable;
-        @NonNull private String mContentDescription = "";
+        @NonNull private CharSequence mContentDescription = "";
         @NonNull private DpProp mSize = DEFAULT_BUTTON_SIZE;
         @Nullable private String mText = null;
         private @TypographyName int mTypographyName =
@@ -119,7 +119,7 @@
          * this for button containing icon or image.
          */
         @NonNull
-        public Builder setContentDescription(@NonNull String contentDescription) {
+        public Builder setContentDescription(@NonNull CharSequence contentDescription) {
             this.mContentDescription = contentDescription;
             return this;
         }
@@ -291,10 +291,10 @@
                                                             .setRadius(radiusOf(mSize))
                                                             .build())
                                             .build());
-            if (!mContentDescription.isEmpty()) {
+            if (mContentDescription.length() > 0) {
                 modifiers.setSemantics(
                         new ModifiersBuilders.Semantics.Builder()
-                                .setContentDescription(mContentDescription)
+                                .setContentDescription(mContentDescription.toString())
                                 .build());
             }
 
@@ -421,7 +421,7 @@
 
     /** Returns content description for this Button. */
     @NonNull
-    public String getContentDescription() {
+    public CharSequence getContentDescription() {
         return checkNotNull(
                 checkNotNull(checkNotNull(mElement.getModifiers()).getSemantics())
                         .getContentDescription());
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Chip.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Chip.java
index d40dd28..9641542 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Chip.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Chip.java
@@ -69,8 +69,7 @@
  * <p>The Chip is Stadium shape and has a max height designed to take no more than two lines of text
  * of {@link Typography#TYPOGRAPHY_BUTTON} style. The {@link Chip} can have an icon horizontally
  * parallel to the two lines of text. Width of chip can very, and the recommended size is screen
- * dependent with the recommended margin being defined in {@link
- * ChipDefaults#DEFAULT_MARGIN_PERCENT} which is set by default.
+ * dependent with the recommended margin being applied.
  *
  * <p>The recommended set of {@link ChipColors} styles can be obtained from {@link ChipDefaults}.,
  * e.g. {@link ChipDefaults#PRIMARY} to get a color scheme for a primary {@link Chip}.
@@ -102,7 +101,7 @@
         @NonNull private String mPrimaryText = "";
         @Nullable private String mLabelText = null;
         @NonNull private final Clickable mClickable;
-        @NonNull private String mContentDescription = "";
+        @NonNull private CharSequence mContentDescription = "";
         @NonNull private ContainerDimension mWidth;
         @NonNull private DpProp mHeight = DEFAULT_HEIGHT;
         @NonNull private ChipColors mChipColors = PRIMARY;
@@ -136,18 +135,17 @@
         }
 
         /**
-         * Sets the width of {@link Chip}. If not set, default value will be screen width decreased
-         * by {@link ChipDefaults#DEFAULT_MARGIN_PERCENT}.
+         * Sets the width of {@link Chip}. If not set, default value will be set to fill the screen.
          */
         @NonNull
-        public Builder setWidth(@NonNull DpProp width) {
+        public Builder setWidth(@NonNull ContainerDimension width) {
             mWidth = width;
             return this;
         }
 
         /**
-         * Sets the width of {@link Chip}. If not set, default value will be screen width decreased
-         * by {@link ChipDefaults#DEFAULT_MARGIN_PERCENT}.
+         * Sets the width of {@link TitleChip}. If not set, default value will be set to fill the
+         * screen.
          */
         @NonNull
         public Builder setWidth(@Dimension(unit = DP) float width) {
@@ -171,7 +169,7 @@
          * this for chip containing icon.
          */
         @NonNull
-        public Builder setContentDescription(@NonNull String contentDescription) {
+        public Builder setContentDescription(@NonNull CharSequence contentDescription) {
             this.mContentDescription = contentDescription;
             return this;
         }
@@ -308,13 +306,6 @@
 
         /** Used for creating CompactChip and TitleChip. */
         @NonNull
-        Builder setWidth(@NonNull ContainerDimension width) {
-            this.mWidth = width;
-            return this;
-        }
-
-        /** Used for creating CompactChip and TitleChip. */
-        @NonNull
         Builder setMaxLines(int maxLines) {
             this.mMaxLines = maxLines;
             return this;
@@ -340,10 +331,10 @@
                                                             .setRadius(radiusOf(mHeight))
                                                             .build())
                                             .build());
-            if (!mContentDescription.isEmpty()) {
+            if (mContentDescription.length() > 0) {
                 modifiers.setSemantics(
                         new ModifiersBuilders.Semantics.Builder()
-                                .setContentDescription(mContentDescription)
+                                .setContentDescription(mContentDescription.toString())
                                 .build());
             }
 
@@ -363,7 +354,7 @@
             if (mType == NOT_SET) {
                 throw new IllegalStateException(
                         "No content set. Use setPrimaryTextContent or similar method to add"
-                            + " content");
+                                + " content");
             }
             if (mType == CUSTOM_CONTENT) {
                 return checkNotNull(mCustomContent);
@@ -551,7 +542,7 @@
 
     /** Returns content description of this Chip. */
     @NonNull
-    public String getContentDescription() {
+    public CharSequence getContentDescription() {
         return checkNotNull(
                 checkNotNull(checkNotNull(mElement.getModifiers()).getSemantics())
                         .getContentDescription());
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ChipDefaults.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ChipDefaults.java
index 26dd4fe..4c3989a 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ChipDefaults.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ChipDefaults.java
@@ -19,38 +19,93 @@
 import static androidx.wear.tiles.DimensionBuilders.dp;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
 import androidx.wear.tiles.DimensionBuilders.DpProp;
 
 /** Contains the default values used by chip Tiles components. */
 public class ChipDefaults {
     private ChipDefaults() {}
 
-    /** The default height for standard {@link Chip} */
-    @NonNull public static final DpProp DEFAULT_HEIGHT = dp(52);
+    /**
+     * The default height for standard {@link Chip}
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public static final DpProp DEFAULT_HEIGHT = dp(52);
 
-    /** The default height for standard {@link CompactChip} */
-    @NonNull public static final DpProp COMPACT_HEIGHT = dp(32);
+    /**
+     * The default height for standard {@link CompactChip}
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public static final DpProp COMPACT_HEIGHT = dp(32);
 
-    /** The default height for standard {@link TitleChip} */
-    @NonNull public static final DpProp TITLE_HEIGHT = dp(60);
+    /**
+     * The default height for standard {@link TitleChip}
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public static final DpProp TITLE_HEIGHT = dp(60);
 
-    /** The recommended horizontal margin used for width for standard {@link Chip} */
+    /**
+     * The recommended horizontal margin used for width for standard {@link Chip}
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
     public static final float DEFAULT_MARGIN_PERCENT = 5.2f;
 
-    /** The recommended horizontal padding for standard {@link Chip} */
-    @NonNull public static final DpProp HORIZONTAL_PADDING = dp(14);
+    /**
+     * The recommended horizontal padding for standard {@link Chip}
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public static final DpProp HORIZONTAL_PADDING = dp(14);
 
-    /** The recommended horizontal padding for standard {@link CompactChip} */
-    @NonNull public static final DpProp COMPACT_HORIZONTAL_PADDING = dp(12);
+    /**
+     * The recommended horizontal padding for standard {@link CompactChip}
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public static final DpProp COMPACT_HORIZONTAL_PADDING = dp(12);
 
-    /** The recommended horizontal padding for standard {@link TitleChip} */
-    @NonNull public static final DpProp TITLE_HORIZONTAL_PADDING = dp(16);
+    /**
+     * The recommended horizontal padding for standard {@link TitleChip}
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public static final DpProp TITLE_HORIZONTAL_PADDING = dp(16);
 
-    /** The recommended vertical space between icon and text in standard {@link Chip} */
-    @NonNull public static final DpProp ICON_SPACER_WIDTH = dp(6);
+    /**
+     * The recommended vertical space between icon and text in standard {@link Chip}
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public static final DpProp ICON_SPACER_WIDTH = dp(6);
 
-    /** The icon size used in standard {@link Chip} */
-    @NonNull public static final DpProp ICON_SIZE = dp(24);
+    /**
+     * The icon size used in standard {@link Chip}
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public static final DpProp ICON_SIZE = dp(24);
 
     /** The recommended colors for a primary {@link Chip}. */
     @NonNull
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CircularProgressIndicator.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CircularProgressIndicator.java
index 09f6dc5..4cc33e6 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CircularProgressIndicator.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CircularProgressIndicator.java
@@ -73,7 +73,7 @@
     public static final class Builder implements LayoutElement.Builder {
         @NonNull private ProgressIndicatorColors mCircularProgressIndicatorColors = DEFAULT_COLOR;
         @NonNull private DpProp mStrokeWidth = DEFAULT_STROKE_WIDTH;
-        @NonNull private String mContentDescription = "";
+        @NonNull private CharSequence mContentDescription = "";
         @NonNull private DegreesProp mStartAngle = degrees(DEFAULT_START_ANGLE);
         @NonNull private DegreesProp mEndAngle = degrees(DEFAULT_END_ANGLE);
 
@@ -122,7 +122,7 @@
          * accessibility support.
          */
         @NonNull
-        public Builder setContentDescription(@NonNull String contentDescription) {
+        public Builder setContentDescription(@NonNull CharSequence contentDescription) {
             this.mContentDescription = contentDescription;
             return this;
         }
@@ -180,7 +180,7 @@
                                             .setSemantics(
                                                     new Semantics.Builder()
                                                             .setContentDescription(
-                                                                    mContentDescription)
+                                                                    mContentDescription.toString())
                                                             .build())
                                             .setPadding(
                                                     new Padding.Builder()
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CompactChip.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CompactChip.java
index 1bd666e..7a9d7c6 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CompactChip.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/CompactChip.java
@@ -27,7 +27,6 @@
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
 import androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters;
-import androidx.wear.tiles.DimensionBuilders.ContainerDimension;
 import androidx.wear.tiles.DimensionBuilders.WrappedDimensionProp;
 import androidx.wear.tiles.LayoutElementBuilders.LayoutElement;
 import androidx.wear.tiles.ModifiersBuilders.Clickable;
@@ -41,8 +40,8 @@
  * size.
  *
  * <p>The recommended set of {@link ChipColors} styles can be obtained from {@link ChipDefaults}.,
- * e.g. {@link ChipDefaults#COMPACT_PRIMARY} to get a color scheme for a primary
- * {@link CompactChip}.
+ * e.g. {@link ChipDefaults#COMPACT_PRIMARY} to get a color scheme for a primary {@link
+ * CompactChip}.
  */
 public class CompactChip implements LayoutElement {
     @NonNull private final Chip mElement;
@@ -112,18 +111,6 @@
         }
     }
 
-    /** Returns height of this Chip. */
-    @NonNull
-    public ContainerDimension getHeight() {
-        return mElement.getHeight();
-    }
-
-    /** Returns width of this Chip. */
-    @NonNull
-    public ContainerDimension getWidth() {
-        return mElement.getWidth();
-    }
-
     /** Returns click event action associated with this Chip. */
     @NonNull
     public Clickable getClickable() {
@@ -136,12 +123,6 @@
         return mElement.getChipColors();
     }
 
-    /** Returns content description of this Chip. */
-    @NonNull
-    public String getContentDescription() {
-        return mElement.getContentDescription();
-    }
-
     /** Returns content of this Chip. */
     @NonNull
     public LayoutElement getContent() {
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ProgressIndicatorDefaults.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ProgressIndicatorDefaults.java
index 6a2a892..1c0c280 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ProgressIndicatorDefaults.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ProgressIndicatorDefaults.java
@@ -21,6 +21,8 @@
 import static androidx.wear.tiles.material.Colors.SURFACE;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
 import androidx.wear.tiles.DimensionBuilders.DpProp;
 
 /** Contains the default values used by {@link CircularProgressIndicator} Tiles components. */
@@ -30,8 +32,14 @@
     /** The default stroke width for {@link CircularProgressIndicator} */
     @NonNull public static final DpProp DEFAULT_STROKE_WIDTH = dp(8);
 
-    /** The default padding for {@link CircularProgressIndicator} */
-    @NonNull public static final DpProp DEFAULT_PADDING = dp(6);
+    /**
+     * The default padding for {@link CircularProgressIndicator}
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public static final DpProp DEFAULT_PADDING = dp(6);
 
     /** The recommended colors for {@link CircularProgressIndicator}. */
     @NonNull
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/TitleChip.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/TitleChip.java
index 830ebd6..b3ead06 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/TitleChip.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/TitleChip.java
@@ -32,7 +32,6 @@
 import androidx.annotation.RestrictTo.Scope;
 import androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters;
 import androidx.wear.tiles.DimensionBuilders.ContainerDimension;
-import androidx.wear.tiles.DimensionBuilders.DpProp;
 import androidx.wear.tiles.LayoutElementBuilders.HorizontalAlignment;
 import androidx.wear.tiles.LayoutElementBuilders.LayoutElement;
 import androidx.wear.tiles.ModifiersBuilders.Clickable;
@@ -65,7 +64,7 @@
 
         // Indicates that the width isn't set, so it will be automatically set by Chip.Builder
         // constructor.
-        @Nullable private DpProp mWidth = null;
+        @Nullable private ContainerDimension mWidth = null;
 
         /**
          * Creates a builder for the {@link TitleChip} with associated action and the given text
@@ -109,18 +108,18 @@
         }
 
         /**
-         * Sets the width of {@link TitleChip}. If not set, default value will be screen width
-         * decreased by {@link ChipDefaults#DEFAULT_MARGIN_PERCENT}.
+         * Sets the width of {@link TitleChip}. If not set, default value will be set to fill the
+         * screen.
          */
         @NonNull
-        public Builder setWidth(@NonNull DpProp width) {
+        public Builder setWidth(@NonNull ContainerDimension width) {
             mWidth = width;
             return this;
         }
 
         /**
-         * Sets the width of {@link TitleChip}. If not set, default value will be screen width
-         * decreased by {@link ChipDefaults#DEFAULT_MARGIN_PERCENT}.
+         * Sets the width of {@link TitleChip}. If not set, default value will be set to fill the
+         * screen.
          */
         @NonNull
         public Builder setWidth(@Dimension(unit = DP) float width) {
@@ -152,12 +151,6 @@
         }
     }
 
-    /** Returns height of this Chip. */
-    @NonNull
-    public ContainerDimension getHeight() {
-        return mElement.getHeight();
-    }
-
     /** Returns width of this Chip. */
     @NonNull
     public ContainerDimension getWidth() {
@@ -176,12 +169,6 @@
         return mElement.getChipColors();
     }
 
-    /** Returns content description of this Chip. */
-    @NonNull
-    public String getContentDescription() {
-        return mElement.getContentDescription();
-    }
-
     /** Returns content of this Chip. */
     @NonNull
     public LayoutElement getContent() {
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Typography.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Typography.java
index 260a1e5..8941e70 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Typography.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/Typography.java
@@ -19,6 +19,8 @@
 import static androidx.annotation.Dimension.DP;
 import static androidx.annotation.Dimension.SP;
 import static androidx.wear.tiles.DimensionBuilders.sp;
+import static androidx.wear.tiles.LayoutElementBuilders.FONT_VARIANT_BODY;
+import static androidx.wear.tiles.LayoutElementBuilders.FONT_VARIANT_TITLE;
 import static androidx.wear.tiles.LayoutElementBuilders.FONT_WEIGHT_BOLD;
 import static androidx.wear.tiles.LayoutElementBuilders.FONT_WEIGHT_MEDIUM;
 import static androidx.wear.tiles.LayoutElementBuilders.FONT_WEIGHT_NORMAL;
@@ -35,6 +37,7 @@
 import androidx.wear.tiles.DimensionBuilders;
 import androidx.wear.tiles.DimensionBuilders.SpProp;
 import androidx.wear.tiles.LayoutElementBuilders.FontStyle;
+import androidx.wear.tiles.LayoutElementBuilders.FontVariant;
 import androidx.wear.tiles.LayoutElementBuilders.FontWeight;
 
 import java.lang.annotation.Retention;
@@ -198,84 +201,98 @@
     private static FontStyle.Builder createFontStyleBuilder(
             @Dimension(unit = SP) int size,
             @FontWeight int weight,
+            @FontVariant int variant,
             float letterSpacing,
             boolean isScalable,
             @NonNull Context context) {
         return new FontStyle.Builder()
                 .setSize(isScalable ? DimensionBuilders.sp(size) : dpToSp(context, size))
                 .setLetterSpacing(DimensionBuilders.em(letterSpacing))
+                .setVariant(variant)
                 .setWeight(weight);
     }
 
     /** Font style for large display text. */
     @NonNull
     private static FontStyle.Builder display1(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(40, FONT_WEIGHT_MEDIUM, 0.01f, isScalable, context);
+        return createFontStyleBuilder(
+                40, FONT_WEIGHT_MEDIUM, FONT_VARIANT_TITLE, 0.01f, isScalable, context);
     }
 
     /** Font style for medium display text. */
     @NonNull
     private static FontStyle.Builder display2(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(34, FONT_WEIGHT_MEDIUM, 0.03f, isScalable, context);
+        return createFontStyleBuilder(
+                34, FONT_WEIGHT_MEDIUM, FONT_VARIANT_TITLE, 0.03f, isScalable, context);
     }
 
     /** Font style for small display text. */
     @NonNull
     private static FontStyle.Builder display3(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(30, FONT_WEIGHT_MEDIUM, 0.03f, isScalable, context);
+        return createFontStyleBuilder(
+                30, FONT_WEIGHT_MEDIUM, FONT_VARIANT_TITLE, 0.03f, isScalable, context);
     }
 
     /** Font style for large title text. */
     @NonNull
     private static FontStyle.Builder title1(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(24, FONT_WEIGHT_MEDIUM, 0.008f, isScalable, context);
+        return createFontStyleBuilder(
+                24, FONT_WEIGHT_MEDIUM, FONT_VARIANT_TITLE, 0.008f, isScalable, context);
     }
 
     /** Font style for medium title text. */
     @NonNull
     private static FontStyle.Builder title2(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(20, FONT_WEIGHT_MEDIUM, 0.01f, isScalable, context);
+        return createFontStyleBuilder(
+                20, FONT_WEIGHT_MEDIUM, FONT_VARIANT_TITLE, 0.01f, isScalable, context);
     }
 
     /** Font style for small title text. */
     @NonNull
     private static FontStyle.Builder title3(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(16, FONT_WEIGHT_MEDIUM, 0.01f, isScalable, context);
+        return createFontStyleBuilder(
+                16, FONT_WEIGHT_MEDIUM, FONT_VARIANT_TITLE, 0.01f, isScalable, context);
     }
 
     /** Font style for normal body text. */
     @NonNull
     private static FontStyle.Builder body1(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(16, FONT_WEIGHT_NORMAL, 0.01f, isScalable, context);
+        return createFontStyleBuilder(
+                16, FONT_WEIGHT_NORMAL, FONT_VARIANT_BODY, 0.01f, isScalable, context);
     }
 
     /** Font style for small body text. */
     @NonNull
     private static FontStyle.Builder body2(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(14, FONT_WEIGHT_NORMAL, 0.014f, isScalable, context);
+        return createFontStyleBuilder(
+                14, FONT_WEIGHT_NORMAL, FONT_VARIANT_BODY, 0.014f, isScalable, context);
     }
 
     /** Font style for bold button text. */
     @NonNull
     private static FontStyle.Builder button(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(15, FONT_WEIGHT_BOLD, 0.03f, isScalable, context);
+        return createFontStyleBuilder(
+                15, FONT_WEIGHT_BOLD, FONT_VARIANT_BODY, 0.03f, isScalable, context);
     }
 
     /** Font style for large caption text. */
     @NonNull
     private static FontStyle.Builder caption1(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(14, FONT_WEIGHT_MEDIUM, 0.01f, isScalable, context);
+        return createFontStyleBuilder(
+                14, FONT_WEIGHT_MEDIUM, FONT_VARIANT_BODY, 0.01f, isScalable, context);
     }
 
     /** Font style for medium caption text. */
     @NonNull
     private static FontStyle.Builder caption2(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(12, FONT_WEIGHT_MEDIUM, 0.01f, isScalable, context);
+        return createFontStyleBuilder(
+                12, FONT_WEIGHT_MEDIUM, FONT_VARIANT_BODY, 0.01f, isScalable, context);
     }
 
     /** Font style for small caption text. */
     @NonNull
     private static FontStyle.Builder caption3(boolean isScalable, @NonNull Context context) {
-        return createFontStyleBuilder(10, FONT_WEIGHT_MEDIUM, 0.01f, isScalable, context);
+        return createFontStyleBuilder(
+                10, FONT_WEIGHT_MEDIUM, FONT_VARIANT_BODY, 0.01f, isScalable, context);
     }
 }
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiSlotLayout.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiSlotLayout.java
index 246f664..f913e63 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiSlotLayout.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/MultiSlotLayout.java
@@ -33,12 +33,9 @@
 import androidx.wear.tiles.DimensionBuilders.DpProp;
 import androidx.wear.tiles.LayoutElementBuilders;
 import androidx.wear.tiles.LayoutElementBuilders.Box;
-import androidx.wear.tiles.LayoutElementBuilders.Layout;
 import androidx.wear.tiles.LayoutElementBuilders.LayoutElement;
 import androidx.wear.tiles.LayoutElementBuilders.Row;
 import androidx.wear.tiles.LayoutElementBuilders.Spacer;
-import androidx.wear.tiles.TimelineBuilders.Timeline;
-import androidx.wear.tiles.TimelineBuilders.TimelineEntry;
 import androidx.wear.tiles.proto.LayoutElementProto;
 
 import java.util.ArrayList;
@@ -175,7 +172,7 @@
                 layoutBuilder.setSecondaryLabelTextContent(mSecondaryLabelText);
             }
 
-            if (mSlotsContent.size() > 0) {
+            if (!mSlotsContent.isEmpty()) {
                 float horizontalPadding = layoutBuilder.getHorizontalPadding();
                 DpProp rowWidth = dp(mDeviceParameters.getScreenWidthDp() - horizontalPadding * 2);
                 Row.Builder rowBuilder =
@@ -207,42 +204,6 @@
         }
     }
 
-    /** Returns the {@link Layout} object containing this layout template. */
-    @NonNull
-    public Layout toLayout() {
-        return toLayoutBuilder().build();
-    }
-
-    /** Returns the {@link Layout.Builder} object containing this layout template. */
-    @NonNull
-    public Layout.Builder toLayoutBuilder() {
-        return new Layout.Builder().setRoot(mElement);
-    }
-
-    /** Returns the {@link TimelineEntry.Builder} object containing this layout template. */
-    @NonNull
-    public TimelineEntry.Builder toTimelineEntryBuilder() {
-        return new TimelineEntry.Builder().setLayout(toLayout());
-    }
-
-    /** Returns the {@link TimelineEntry} object containing this layout template. */
-    @NonNull
-    public TimelineEntry toTimelineEntry() {
-        return toTimelineEntryBuilder().build();
-    }
-
-    /** Returns the {@link Timeline.Builder} object containing this layout template. */
-    @NonNull
-    public Timeline.Builder toTimelineBuilder() {
-        return new Timeline.Builder().addTimelineEntry(toTimelineEntry());
-    }
-
-    /** Returns the {@link Timeline} object containing this layout template. */
-    @NonNull
-    public Timeline toTimeline() {
-        return toTimelineBuilder().build();
-    }
-
     /** @hide */
     @NonNull
     @Override
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/PrimaryLayout.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/PrimaryLayout.java
index 585f8f2..90245c3 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/PrimaryLayout.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/PrimaryLayout.java
@@ -43,13 +43,10 @@
 import androidx.wear.tiles.LayoutElementBuilders;
 import androidx.wear.tiles.LayoutElementBuilders.Box;
 import androidx.wear.tiles.LayoutElementBuilders.Column;
-import androidx.wear.tiles.LayoutElementBuilders.Layout;
 import androidx.wear.tiles.LayoutElementBuilders.LayoutElement;
 import androidx.wear.tiles.LayoutElementBuilders.Spacer;
 import androidx.wear.tiles.ModifiersBuilders.Modifiers;
 import androidx.wear.tiles.ModifiersBuilders.Padding;
-import androidx.wear.tiles.TimelineBuilders.Timeline;
-import androidx.wear.tiles.TimelineBuilders.TimelineEntry;
 import androidx.wear.tiles.material.CompactChip;
 import androidx.wear.tiles.proto.LayoutElementProto;
 
@@ -267,42 +264,6 @@
         }
     }
 
-    /** Returns the {@link Layout} object containing this layout template. */
-    @NonNull
-    public Layout toLayout() {
-        return toLayoutBuilder().build();
-    }
-
-    /** Returns the {@link Layout.Builder} object containing this layout template. */
-    @NonNull
-    public Layout.Builder toLayoutBuilder() {
-        return new Layout.Builder().setRoot(mElement);
-    }
-
-    /** Returns the {@link TimelineEntry.Builder} object containing this layout template. */
-    @NonNull
-    public TimelineEntry.Builder toTimelineEntryBuilder() {
-        return new TimelineEntry.Builder().setLayout(toLayout());
-    }
-
-    /** Returns the {@link TimelineEntry} object containing this layout template. */
-    @NonNull
-    public TimelineEntry toTimelineEntry() {
-        return toTimelineEntryBuilder().build();
-    }
-
-    /** Returns the {@link Timeline.Builder} object containing this layout template. */
-    @NonNull
-    public Timeline.Builder toTimelineBuilder() {
-        return new Timeline.Builder().addTimelineEntry(toTimelineEntry());
-    }
-
-    /** Returns the {@link Timeline} object containing this layout template. */
-    @NonNull
-    public Timeline toTimeline() {
-        return toTimelineBuilder().build();
-    }
-
     /** @hide */
     @NonNull
     @Override
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/ProgressIndicatorLayout.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/ProgressIndicatorLayout.java
index 06e41d0..cc0d270 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/ProgressIndicatorLayout.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/ProgressIndicatorLayout.java
@@ -32,12 +32,9 @@
 import androidx.wear.tiles.DimensionBuilders.DpProp;
 import androidx.wear.tiles.LayoutElementBuilders;
 import androidx.wear.tiles.LayoutElementBuilders.Box;
-import androidx.wear.tiles.LayoutElementBuilders.Layout;
 import androidx.wear.tiles.LayoutElementBuilders.LayoutElement;
 import androidx.wear.tiles.ModifiersBuilders.Modifiers;
 import androidx.wear.tiles.ModifiersBuilders.Padding;
-import androidx.wear.tiles.TimelineBuilders.Timeline;
-import androidx.wear.tiles.TimelineBuilders.TimelineEntry;
 import androidx.wear.tiles.material.CircularProgressIndicator;
 import androidx.wear.tiles.proto.LayoutElementProto;
 
@@ -152,42 +149,6 @@
         }
     }
 
-    /** Returns the {@link Layout} object containing this layout template. */
-    @NonNull
-    public Layout toLayout() {
-        return toLayoutBuilder().build();
-    }
-
-    /** Returns the {@link Layout.Builder} object containing this layout template. */
-    @NonNull
-    public Layout.Builder toLayoutBuilder() {
-        return new Layout.Builder().setRoot(mElement);
-    }
-
-    /** Returns the {@link TimelineEntry.Builder} object containing this layout template. */
-    @NonNull
-    public TimelineEntry.Builder toTimelineEntryBuilder() {
-        return new TimelineEntry.Builder().setLayout(toLayout());
-    }
-
-    /** Returns the {@link TimelineEntry} object containing this layout template. */
-    @NonNull
-    public TimelineEntry toTimelineEntry() {
-        return toTimelineEntryBuilder().build();
-    }
-
-    /** Returns the {@link Timeline.Builder} object containing this layout template. */
-    @NonNull
-    public Timeline.Builder toTimelineBuilder() {
-        return new Timeline.Builder().addTimelineEntry(toTimelineEntry());
-    }
-
-    /** Returns the {@link Timeline} object containing this layout template. */
-    @NonNull
-    public Timeline toTimeline() {
-        return toTimelineBuilder().build();
-    }
-
     /** Get the inner content from this layout. */
     @NonNull
     public LayoutElement getContent() {
diff --git a/wear/tiles/tiles/api/current.txt b/wear/tiles/tiles/api/current.txt
index 37c11ec..d2a5bf8 100644
--- a/wear/tiles/tiles/api/current.txt
+++ b/wear/tiles/tiles/api/current.txt
@@ -554,6 +554,7 @@
   }
 
   public static final class LayoutElementBuilders.Layout {
+    method public static androidx.wear.tiles.LayoutElementBuilders.Layout fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getRoot();
   }
 
@@ -1001,6 +1002,7 @@
   }
 
   public static final class TimelineBuilders.Timeline {
+    method public static androidx.wear.tiles.TimelineBuilders.Timeline fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     method public java.util.List<androidx.wear.tiles.TimelineBuilders.TimelineEntry!> getTimelineEntries();
   }
 
@@ -1011,6 +1013,7 @@
   }
 
   public static final class TimelineBuilders.TimelineEntry {
+    method public static androidx.wear.tiles.TimelineBuilders.TimelineEntry fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     method public androidx.wear.tiles.LayoutElementBuilders.Layout? getLayout();
     method public androidx.wear.tiles.TimelineBuilders.TimeInterval? getValidity();
   }
diff --git a/wear/tiles/tiles/api/public_plus_experimental_current.txt b/wear/tiles/tiles/api/public_plus_experimental_current.txt
index 161cb59..9b585a1 100644
--- a/wear/tiles/tiles/api/public_plus_experimental_current.txt
+++ b/wear/tiles/tiles/api/public_plus_experimental_current.txt
@@ -568,6 +568,7 @@
   }
 
   public static final class LayoutElementBuilders.Layout {
+    method public static androidx.wear.tiles.LayoutElementBuilders.Layout fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getRoot();
   }
 
@@ -1018,6 +1019,7 @@
   }
 
   public static final class TimelineBuilders.Timeline {
+    method public static androidx.wear.tiles.TimelineBuilders.Timeline fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     method public java.util.List<androidx.wear.tiles.TimelineBuilders.TimelineEntry!> getTimelineEntries();
   }
 
@@ -1028,6 +1030,7 @@
   }
 
   public static final class TimelineBuilders.TimelineEntry {
+    method public static androidx.wear.tiles.TimelineBuilders.TimelineEntry fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     method public androidx.wear.tiles.LayoutElementBuilders.Layout? getLayout();
     method public androidx.wear.tiles.TimelineBuilders.TimeInterval? getValidity();
   }
diff --git a/wear/tiles/tiles/api/restricted_current.txt b/wear/tiles/tiles/api/restricted_current.txt
index 37c11ec..d2a5bf8 100644
--- a/wear/tiles/tiles/api/restricted_current.txt
+++ b/wear/tiles/tiles/api/restricted_current.txt
@@ -554,6 +554,7 @@
   }
 
   public static final class LayoutElementBuilders.Layout {
+    method public static androidx.wear.tiles.LayoutElementBuilders.Layout fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getRoot();
   }
 
@@ -1001,6 +1002,7 @@
   }
 
   public static final class TimelineBuilders.Timeline {
+    method public static androidx.wear.tiles.TimelineBuilders.Timeline fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     method public java.util.List<androidx.wear.tiles.TimelineBuilders.TimelineEntry!> getTimelineEntries();
   }
 
@@ -1011,6 +1013,7 @@
   }
 
   public static final class TimelineBuilders.TimelineEntry {
+    method public static androidx.wear.tiles.TimelineBuilders.TimelineEntry fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     method public androidx.wear.tiles.LayoutElementBuilders.Layout? getLayout();
     method public androidx.wear.tiles.TimelineBuilders.TimeInterval? getValidity();
   }
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/LayoutElementBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/LayoutElementBuilders.java
index d696c43..1da6e2a 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/LayoutElementBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/LayoutElementBuilders.java
@@ -3579,6 +3579,12 @@
             return new Layout(proto);
         }
 
+        /** Returns the {@link Layout} object containing the given layout element. */
+        @NonNull
+        public static Layout fromLayoutElement(@NonNull LayoutElement layoutElement) {
+            return new Builder().setRoot(layoutElement).build();
+        }
+
         /** @hide */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
diff --git a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TimelineBuilders.java b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TimelineBuilders.java
index 7902f89..647d4cc 100644
--- a/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TimelineBuilders.java
+++ b/wear/tiles/tiles/src/main/java/androidx/wear/tiles/TimelineBuilders.java
@@ -139,6 +139,15 @@
             return new TimelineEntry(proto);
         }
 
+        /** Returns the {@link TimelineEntry} object containing the given layout element. */
+        @NonNull
+        public static TimelineEntry fromLayoutElement(
+                @NonNull LayoutElementBuilders.LayoutElement layoutElement
+        ) {
+            return new Builder()
+                    .setLayout(Layout.fromLayoutElement(layoutElement)).build();
+        }
+
         /** @hide */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -212,6 +221,15 @@
             return new Timeline(proto);
         }
 
+        /** Returns the {@link Timeline} object containing the given layout element. */
+        @NonNull
+        public static Timeline fromLayoutElement(
+                @NonNull LayoutElementBuilders.LayoutElement layoutElement
+        ) {
+            return new Builder()
+                    .addTimelineEntry(TimelineEntry.fromLayoutElement(layoutElement)).build();
+        }
+
         /** @hide */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
diff --git a/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java b/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java
index 95e0c14..8ede3a8 100644
--- a/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java
+++ b/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationRenderer.java
@@ -177,8 +177,11 @@
     private RoundedDrawable mRoundedSmallImage = null;
 
     // Text renderers
-    private final TextRenderer mMainTextRenderer = new TextRenderer();
-    private final TextRenderer mSubTextRenderer = new TextRenderer();
+    @VisibleForTesting
+    TextRenderer mMainTextRenderer = new TextRenderer();
+
+    @VisibleForTesting
+    TextRenderer mSubTextRenderer = new TextRenderer();
 
     // Bounds for components. NB we want to avoid allocations in watch face rendering code to
     // reduce GC pressure.
@@ -195,8 +198,10 @@
     // Paint sets for active and ambient modes.
     @VisibleForTesting
     PaintSet mActivePaintSet = null;
+    PaintSet mActivePaintSetLostTapAction = null;
     @VisibleForTesting
     PaintSet mAmbientPaintSet = null;
+    PaintSet mAmbientPaintSetLostTapAction = null;
 
     // Paints for texts
     @Nullable
@@ -244,7 +249,11 @@
         mAmbientStyle = ambientStyle;
         // Reset paint sets
         mActivePaintSet = new PaintSet(activeStyle, false, false, false);
+        mActivePaintSetLostTapAction =
+                new PaintSet(activeStyle.asTinted(Color.DKGRAY), false, false, false);
         mAmbientPaintSet = new PaintSet(ambientStyle, true, false, false);
+        mAmbientPaintSetLostTapAction =
+                new PaintSet(activeStyle.asTinted(Color.DKGRAY), true, false, false);
         calculateBounds();
     }
 
@@ -422,9 +431,9 @@
             mAmbientPaintSet = new PaintSet(mAmbientStyle, true, lowBitAmbient, burnInProtection);
         }
         // Choose the correct paint set to use
-        PaintSet currentPaintSet = inAmbientMode ? mAmbientPaintSet : mActivePaintSet;
-        currentPaintSet.setAlpha(
-                mComplicationData.getTapActionLostDueToSerialization() ? 128 : 255);
+        PaintSet currentPaintSet = mComplicationData.getTapActionLostDueToSerialization()
+                ? (inAmbientMode ? mAmbientPaintSetLostTapAction : mActivePaintSetLostTapAction) :
+                (inAmbientMode ? mAmbientPaintSet : mActivePaintSet);
         // Update complication texts
         updateComplicationTexts(currentTime.toEpochMilli());
         canvas.save();
@@ -652,7 +661,7 @@
             }
             icon.setColorFilter(mComplicationData.hasPlaceholderType() ? PLACEHOLDER_COLOR_FILTER :
                     paintSet.mIconColorFilter);
-            drawIconOnCanvas(canvas, mIconBounds, icon, paintSet.getAlpha());
+            drawIconOnCanvas(canvas, mIconBounds, icon);
         } else if (isPlaceholder) {
             canvas.drawRect(mIconBounds, PLACEHOLDER_PAINT);
         }
@@ -717,11 +726,10 @@
         }
     }
 
-    private static void drawIconOnCanvas(Canvas canvas, Rect bounds, Drawable icon, int alpha) {
+    private static void drawIconOnCanvas(Canvas canvas, Rect bounds, Drawable icon) {
         icon.setBounds(0, 0, bounds.width(), bounds.height());
         canvas.save();
         canvas.translate(bounds.left, bounds.top);
-        icon.setAlpha(alpha);
         icon.draw(canvas);
         canvas.restore();
     }
@@ -1075,9 +1083,6 @@
         /** Icon tint color filter */
         final ColorFilter mIconColorFilter;
 
-        /** The alpha value to render with */
-        int mAlpha;
-
         @SuppressLint("SyntheticAccessor")
         PaintSet(
                 ComplicationStyle style,
@@ -1151,19 +1156,6 @@
             mHighlightPaint.setAntiAlias(antiAlias);
         }
 
-        void setAlpha(int alpha) {
-            mPrimaryTextPaint.setAlpha(alpha);
-            mSecondaryTextPaint.setAlpha(alpha);
-            mInProgressPaint.setAlpha(alpha);
-            mRemainingPaint.setAlpha(alpha);
-            mBorderPaint.setAlpha(alpha);
-            mAlpha = alpha;
-        }
-
-        int getAlpha() {
-            return mAlpha;
-        }
-
         boolean isInBurnInProtectionMode() {
             return mIsAmbientStyle && mBurnInProtection;
         }
diff --git a/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationStyle.kt b/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationStyle.kt
index 7efd9b1..3e91f21 100644
--- a/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationStyle.kt
+++ b/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/ComplicationStyle.kt
@@ -301,6 +301,22 @@
         isDirty = true
     }
 
+    /**
+     * Returns a copy of the ComplicationStyle [tint]ed by [tintColor].
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    fun asTinted(tintColor: Int): ComplicationStyle = ComplicationStyle(this).apply {
+        backgroundColor = tint(backgroundColor, tintColor)
+        borderColor = tint(borderColor, tintColor)
+        highlightColor = tint(highlightColor, tintColor)
+        iconColor = tint(iconColor, tintColor)
+        rangedValuePrimaryColor = tint(rangedValuePrimaryColor, tintColor)
+        rangedValueSecondaryColor = tint(rangedValueSecondaryColor, tintColor)
+        textColor = tint(textColor, tintColor)
+        titleColor = tint(titleColor, tintColor)
+    }
+
     public companion object {
         /** Style where the borders are not drawn.  */
         public const val BORDER_STYLE_NONE: Int = 0
@@ -357,5 +373,20 @@
         /** Default border radius.  */
         @Px
         public const val BORDER_RADIUS_DEFAULT: Int = Int.MAX_VALUE
+
+        /** Computes the luminance of [color] and applies that to [tint]. */
+        internal fun tint(color: Int, tint: Int): Int {
+            // See https://en.wikipedia.org/wiki/Relative_luminance
+            val luminance = (Color.red(color).toFloat() * (0.2126f / 255.0f)) +
+                (Color.green(color).toFloat() * (0.7152f / 255.0f)) +
+                (Color.blue(color).toFloat() * (0.0722f / 255.0f))
+
+            return Color.argb(
+                Color.alpha(color).toFloat() / 255.0f,
+                Color.red(tint) * luminance / 255.0f,
+                Color.green(tint) * luminance / 255.0f,
+                Color.blue(tint) * luminance / 255.0f
+            )
+        }
     }
 }
\ No newline at end of file
diff --git a/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/TextRenderer.java b/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/TextRenderer.java
index 7e2a415..d5caf43 100644
--- a/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/TextRenderer.java
+++ b/wear/watchface/watchface-complications-rendering/src/main/java/androidx/wear/watchface/complications/rendering/TextRenderer.java
@@ -232,6 +232,11 @@
         mNeedUpdateLayout = true;
     }
 
+    @NonNull
+    public TextPaint getPaint() {
+        return mPaint;
+    }
+
     /**
      * Sets the padding which will be applied to the bounds before the text is drawn. The {@code
      * start} and {@code end} parameters should be given as a proportion of the width of the bounds,
diff --git a/wear/watchface/watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/ComplicationRendererTest.java b/wear/watchface/watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/ComplicationRendererTest.java
index d18845c..d3dd469 100644
--- a/wear/watchface/watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/ComplicationRendererTest.java
+++ b/wear/watchface/watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/ComplicationRendererTest.java
@@ -750,6 +750,44 @@
     }
 
     @Test
+    public void notTintedWhenTapActionNotLostDueToSerialization() {
+        // GIVEN a complication renderer with short text data
+        mComplicationRenderer.setComplicationData(
+                new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+                        .setShortText(ComplicationText.plainText("Test text"))
+                        .setTapActionLostDueToSerialization(false)
+                        .build(),
+                true);
+        // WHEN the complication is drawn in low bit ambient mode
+        mComplicationRenderer.draw(mMockCanvas, REFERENCE_TIME, false, false, false, false);
+
+        assertThat(mComplicationRenderer.mMainTextRenderer.getPaint())
+                .isEqualTo(mComplicationRenderer.mActivePaintSet.mPrimaryTextPaint);
+
+        verify(mMockCanvas, atLeastOnce()).drawRoundRect(any(), anyFloat(), anyFloat(),
+                eq(mComplicationRenderer.mActivePaintSet.mBorderPaint));
+    }
+
+    @Test
+    public void darkTintWhenTapActionLostDueToSerialization() {
+        // GIVEN a complication renderer with short text data
+        mComplicationRenderer.setComplicationData(
+                new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+                        .setShortText(ComplicationText.plainText("Test text"))
+                        .setTapActionLostDueToSerialization(true)
+                        .build(),
+                true);
+        // WHEN the complication is drawn in low bit ambient mode
+        mComplicationRenderer.draw(mMockCanvas, REFERENCE_TIME, false, false, false, false);
+
+        assertThat(mComplicationRenderer.mMainTextRenderer.getPaint())
+                .isEqualTo(mComplicationRenderer.mActivePaintSetLostTapAction.mPrimaryTextPaint);
+
+        verify(mMockCanvas, atLeastOnce()).drawRoundRect(any(), anyFloat(), anyFloat(),
+                eq(mComplicationRenderer.mActivePaintSetLostTapAction.mBorderPaint));
+    }
+
+    @Test
     public void paintSetHasCorrectColorsAndValues() {
         // GIVEN a complication style
         Typeface textTypeface = Typeface.create("sans-serif", Typeface.NORMAL);
diff --git a/wear/watchface/watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/ComplicationStyleTest.kt b/wear/watchface/watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/ComplicationStyleTest.kt
new file mode 100644
index 0000000..34b2ac7
--- /dev/null
+++ b/wear/watchface/watchface-complications-rendering/src/test/java/androidx/wear/watchface/complications/rendering/ComplicationStyleTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.watchface.complications.rendering
+
+import android.graphics.Color
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.annotation.internal.DoNotInstrument
+
+/** Tests for [ComplicationStyle]. */
+@RunWith(ComplicationsTestRunner::class)
+@DoNotInstrument
+class ComplicationStyleTest {
+    @Test
+    public fun tintTest() {
+        assertThat(ComplicationStyle.tint(Color.argb(127, 255, 255, 255), Color.argb(0, 255, 0, 0)))
+            .isEqualTo(Color.argb(127, 255, 0, 0))
+
+        assertThat(ComplicationStyle.tint(Color.argb(127, 255, 255, 255), Color.argb(0, 100, 0, 0)))
+            .isEqualTo(Color.argb(127, 100, 0, 0))
+
+        assertThat(ComplicationStyle.tint(Color.argb(127, 100, 100, 100), Color.argb(0, 255, 0, 0)))
+            .isEqualTo(Color.argb(127, 100, 0, 0))
+
+        assertThat(
+            ComplicationStyle.tint(Color.argb(127, 50, 100, 200), Color.argb(0, 127, 127, 255))
+        ).isEqualTo(Color.argb(127, 48, 48, 97))
+    }
+
+    @Test
+    public fun asTinted() {
+        val complicationStyle = ComplicationStyle()
+        val tintedComplicationStyle = complicationStyle.asTinted(Color.RED)
+
+        assertThat(tintedComplicationStyle.backgroundColor).isEqualTo(Color.BLACK)
+        assertThat(tintedComplicationStyle.borderColor).isEqualTo(Color.RED)
+        assertThat(tintedComplicationStyle.highlightColor)
+            .isEqualTo(ComplicationStyle.tint(Color.LTGRAY, Color.RED))
+        assertThat(tintedComplicationStyle.iconColor).isEqualTo(Color.RED)
+        assertThat(tintedComplicationStyle.rangedValuePrimaryColor).isEqualTo(Color.RED)
+        assertThat(tintedComplicationStyle.rangedValueSecondaryColor)
+            .isEqualTo(ComplicationStyle.tint(Color.LTGRAY, Color.RED))
+        assertThat(tintedComplicationStyle.textColor).isEqualTo(Color.RED)
+        assertThat(tintedComplicationStyle.titleColor)
+            .isEqualTo(ComplicationStyle.tint(Color.LTGRAY, Color.RED))
+    }
+}
\ No newline at end of file
diff --git a/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java b/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
index b3fde0f..8657afa 100644
--- a/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
+++ b/webkit/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
@@ -320,7 +320,6 @@
     public void testGetVariationsHeader() {
         WebkitUtils.checkFeature(WebViewFeature.GET_VARIATIONS_HEADER);
 
-        WebViewOnUiThread.createWebView();
         assertNotNull(WebViewCompat.getVariationsHeader());
     }
 
diff --git a/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt b/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
index b5ff4b2..dd504ae 100644
--- a/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
+++ b/window/window/src/main/java/androidx/window/embedding/EmbeddingAdapter.kt
@@ -127,13 +127,8 @@
             .setSplitRatio(rule.splitRatio)
             .setLayoutDirection(rule.layoutDirection)
             .setShouldClearTop(rule.clearTop)
-
-        try {
-            builder.setFinishPrimaryWithSecondary(rule.finishPrimaryWithSecondary)
-            builder.setFinishSecondaryWithPrimary(rule.finishSecondaryWithPrimary)
-        } catch (error: NoSuchMethodError) {
-            // TODO(b/205181250): Old extension interface, to be dropped with next developer preview
-        }
+            .setFinishPrimaryWithSecondary(rule.finishPrimaryWithSecondary)
+            .setFinishSecondaryWithPrimary(rule.finishSecondaryWithPrimary)
         return builder.build()
     }
 
@@ -155,13 +150,8 @@
         )
             .setSplitRatio(rule.splitRatio)
             .setLayoutDirection(rule.layoutDirection)
-
-        try {
-            builder.setSticky(rule.isSticky)
-            builder.setFinishPrimaryWithSecondary(rule.finishPrimaryWithSecondary)
-        } catch (error: NoSuchMethodError) {
-            // TODO(b/205181250): Old extension interface, to be dropped with next developer preview
-        }
+            .setSticky(rule.isSticky)
+            .setFinishPrimaryWithSecondary(rule.finishPrimaryWithSecondary)
         return builder.build()
     }