Merge "Move CircularIntArrayTest to the right folder" into androidx-main
diff --git a/OWNERS b/OWNERS
index c325dad..6e081c7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -11,6 +11,7 @@
 [email protected]
 [email protected]
 [email protected]
[email protected]
 [email protected]
 [email protected]
 [email protected]
diff --git a/ads/ads-identifier-common/lint-baseline.xml b/ads/ads-identifier-common/lint-baseline.xml
index ed36cbc..5a3573b 100644
--- a/ads/ads-identifier-common/lint-baseline.xml
+++ b/ads/ads-identifier-common/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="PrivateConstructorForUtilityClass"
diff --git a/annotation/annotation-experimental-lint/integration-tests/build.gradle b/annotation/annotation-experimental-lint/integration-tests/build.gradle
index 83a3c34..6e4b361 100644
--- a/annotation/annotation-experimental-lint/integration-tests/build.gradle
+++ b/annotation/annotation-experimental-lint/integration-tests/build.gradle
@@ -26,6 +26,10 @@
     id("kotlin-android")
 }
 
+android {
+    namespace "androidx.annotation.experimental.lint.integrationtests"
+}
+
 dependencies {
     implementation(libs.kotlinStdlib)
     implementation(project(":annotation:annotation-experimental"))
diff --git a/annotation/annotation-experimental-lint/integration-tests/src/main/AndroidManifest.xml b/annotation/annotation-experimental-lint/integration-tests/src/main/AndroidManifest.xml
deleted file mode 100644
index ed18b0e..0000000
--- a/annotation/annotation-experimental-lint/integration-tests/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  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.
--->
-<manifest package="androidx.annotation.experimental.lint.integrationtests" />
diff --git a/appcompat/appcompat-lint/build.gradle b/appcompat/appcompat-lint/build.gradle
index ecd2347..847916f 100644
--- a/appcompat/appcompat-lint/build.gradle
+++ b/appcompat/appcompat-lint/build.gradle
@@ -35,7 +35,6 @@
 androidx {
     name = "AppCompat Lint Checks"
     type = LibraryType.LINT
-    mavenVersion = LibraryVersions.APPCOMPAT
     mavenGroup = LibraryGroups.APPCOMPAT
     inceptionYear = "2019"
     description = "AppCompat Lint Checks"
diff --git a/appcompat/appcompat-resources/build.gradle b/appcompat/appcompat-resources/build.gradle
index db493d4..5ad3701 100644
--- a/appcompat/appcompat-resources/build.gradle
+++ b/appcompat/appcompat-resources/build.gradle
@@ -23,6 +23,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":appcompat:appcompat"))
+    }
+
     api("androidx.annotation:annotation:1.2.0")
     api("androidx.core:core:1.6.0")
     implementation("androidx.collection:collection:1.0.0")
@@ -61,7 +66,6 @@
 androidx {
     name = "Android Resources Library"
     publish = Publish.SNAPSHOT_AND_RELEASE
-    mavenVersion = LibraryVersions.APPCOMPAT
     mavenGroup = LibraryGroups.APPCOMPAT
     inceptionYear = "2019"
     description = "The Resources Library is a static library that you can add to your Android application in order to use resource APIs that backport the latest APIs to older versions of the platform. Compatible on devices running API 14 or later."
diff --git a/appcompat/appcompat/build.gradle b/appcompat/appcompat/build.gradle
index 2a38d52..5ad588a 100644
--- a/appcompat/appcompat/build.gradle
+++ b/appcompat/appcompat/build.gradle
@@ -8,6 +8,11 @@
 }
 
 dependencies {
+    // Atomic group
+    constraints {
+        implementation(project(":appcompat:appcompat-resources"))
+    }
+
     api("androidx.annotation:annotation:1.3.0")
     api(projectOrArtifact(":core:core"))
 
@@ -40,6 +45,7 @@
     androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it's own MockMaker
     androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has it's own MockMaker
     androidTestImplementation("androidx.lifecycle:lifecycle-runtime-testing:2.3.1" )
+    androidTestImplementation(project(":internal-testutils-runtime"))
     androidTestImplementation(project(":internal-testutils-appcompat"), {
         exclude group: "androidx.appcompat", module: "appcompat"
         exclude group: "androidx.core", module: "core"
@@ -86,12 +92,12 @@
     useLibrary "android.test.base"
     useLibrary "android.test.mock"
     namespace "androidx.appcompat"
+    testNamespace "androidx.appcompat.test"
 }
 
 androidx {
     name = "Android AppCompat Library"
     publish = Publish.SNAPSHOT_AND_RELEASE
-    mavenVersion = LibraryVersions.APPCOMPAT
     mavenGroup = LibraryGroups.APPCOMPAT
     inceptionYear = "2011"
     description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
diff --git a/appcompat/appcompat/src/androidTest/AndroidManifest.xml b/appcompat/appcompat/src/androidTest/AndroidManifest.xml
index 7749326..d128244 100644
--- a/appcompat/appcompat/src/androidTest/AndroidManifest.xml
+++ b/appcompat/appcompat/src/androidTest/AndroidManifest.xml
@@ -238,6 +238,17 @@
             android:name="androidx.appcompat.app.FragmentContentIdActivity"/>
 
         <activity
+            android:name="androidx.appcompat.app.g3.FilternatorActivity"
+            android:configChanges="orientation|screenSize|keyboardHidden"/>
+
+        <activity
+            android:name="androidx.appcompat.app.g3.OldTranslateActivity"
+            android:configChanges="screenSize|keyboardHidden|orientation|smallestScreenSize|screenLayout"
+            android:recreateOnConfigChanges="mcc|mnc"
+            android:documentLaunchMode="never"
+            android:windowSoftInputMode="adjustNothing"/>
+
+        <activity
             android:name="androidx.appcompat.app.NightModeActivity"
             android:theme="@style/Theme.AppCompat.DayNight"/>
 
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/AlertDialogTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/AlertDialogTest.java
index 5ee9d78..f57d8fe 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/AlertDialogTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/AlertDialogTest.java
@@ -89,6 +89,7 @@
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -1384,6 +1385,7 @@
      * successfully when the foreground color is a CSL and that the color is used for the scroll
      * indicator tint.
      */
+    @Ignore("b/236995180")
     @Test
     @UiThreadTest
     @SdkSuppress(maxSdkVersion = 22)
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/DrawerDynamicLayoutTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/DrawerDynamicLayoutTest.java
index a379cce..851fbe9 100755
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/DrawerDynamicLayoutTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/DrawerDynamicLayoutTest.java
@@ -139,15 +139,6 @@
                 inflateViewStub(R.layout.drawer_dynamic_content_single_start));
     }
 
-    @Test(expected=IllegalStateException.class)
-    public void testDoubleStartDrawers() {
-        onView(withId(R.id.drawer_layout)).check(doesNotExist());
-        // Note the expected exception in the @Test annotation, as we expect the DrawerLayout
-        // to throw exception during the measure pass as it detects two start drawers.
-        onView(withId(R.id.drawer_stub)).perform(
-                inflateViewStub(R.layout.drawer_dynamic_content_double_start));
-    }
-
     @Test
     public void testSingleEndDrawer() {
         onView(withId(R.id.drawer_layout)).check(doesNotExist());
@@ -155,15 +146,6 @@
                 inflateViewStub(R.layout.drawer_dynamic_content_single_end));
     }
 
-    @Test(expected=IllegalStateException.class)
-    public void testDoubleEndDrawers() {
-        onView(withId(R.id.drawer_layout)).check(doesNotExist());
-        // Note the expected exception in the @Test annotation, as we expect the DrawerLayout
-        // to throw exception during the measure pass as it detects two end drawers.
-        onView(withId(R.id.drawer_stub)).perform(
-                inflateViewStub(R.layout.drawer_dynamic_content_double_end, true));
-    }
-
     @Test
     public void testSingleStartDrawerSingleEndDrawer() {
         onView(withId(R.id.drawer_layout)).check(doesNotExist());
@@ -171,24 +153,6 @@
                 inflateViewStub(R.layout.drawer_dynamic_content_start_end));
     }
 
-    @Test(expected=IllegalStateException.class)
-    public void testDoubleStartDrawersSingleEndDrawer() {
-        onView(withId(R.id.drawer_layout)).check(doesNotExist());
-        // Note the expected exception in the @Test annotation, as we expect the DrawerLayout
-        // to throw exception during the measure pass as it detects two start drawers.
-        onView(withId(R.id.drawer_stub)).perform(
-                inflateViewStub(R.layout.drawer_dynamic_content_double_start_single_end));
-    }
-
-    @Test(expected=IllegalStateException.class)
-    public void testDoubleEndDrawersSingleStartDrawer() {
-        onView(withId(R.id.drawer_layout)).check(doesNotExist());
-        // Note the expected exception in the @Test annotation, as we expect the DrawerLayout
-        // to throw exception during the measure pass as it detects two start drawers.
-        onView(withId(R.id.drawer_stub)).perform(
-                inflateViewStub(R.layout.drawer_dynamic_content_double_end_single_start));
-    }
-
     @Test
     public void testRemoveUnregisteredListener() {
         onView(withId(R.id.drawer_stub)).perform(
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/AndroidTestUtil.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/AndroidTestUtil.java
new file mode 100644
index 0000000..632d5e3
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/AndroidTestUtil.java
@@ -0,0 +1,127 @@
+/*
+ * 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.appcompat.app.g3;
+
+import static androidx.core.util.Preconditions.checkNotNull;
+
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.uiautomator.UiDevice;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Adapted from g3's AndroidTestUtil.java with modifications to pass AndroidX lint.
+ */
+public class AndroidTestUtil {
+    private static final String TAG = AndroidTestUtil.class.getSimpleName();
+    private static final Lock LOCK = new ReentrantLock();
+    private static final Condition CONDITION = LOCK.newCondition();
+
+    /** Represents possible screen orientations. */
+    public enum ScreenOrientation {
+        PORTRAIT(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT),
+        LANDSCAPE(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+
+        private final int mScreenOrientation;
+
+        ScreenOrientation(int screenOrientation) {
+            this.mScreenOrientation = screenOrientation;
+        }
+
+        @SuppressWarnings("unused")
+        private int value() {
+            return this.mScreenOrientation;
+        }
+    }
+
+    /**
+     * Sets the screen orientation.
+     *
+     * <p>This will block the UI-thread until the operation completes, or throw an
+     * InterruptedException after 5 seconds.
+     *
+     * @param context the context of the application.
+     * @param screenOrientation absolute value to set the screen orientation.
+     */
+    @SuppressWarnings("ResultOfMethodCallIgnored")
+    public static void setScreenOrientation(Context context, ScreenOrientation screenOrientation) {
+        checkNotNull(context);
+
+        // This should have been an instanceof Application check when the method was first added,
+        // but it's too hard to back out now. Try really hard to make sure we're using the right
+        // context.
+        Context appContext = context.getApplicationContext();
+
+        // Of course, they might be passing the instrumentation's getContext(), which doesn't have
+        // access to the application context. They should have used getTargetContext()!
+        if (appContext != null) {
+            context = appContext;
+        }
+
+        try {
+            UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+            switch (screenOrientation) {
+                case PORTRAIT:
+                    device.setOrientationNatural();
+                    break;
+                case LANDSCAPE:
+                    device.setOrientationRight();
+                    break;
+            }
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+
+        LOCK.lock(); // block until condition holds
+        try {
+            while (screenOrientation != getScreenOrientation(context)) {
+                CONDITION.await(5, TimeUnit.SECONDS);
+            }
+        } catch (InterruptedException ex) {
+            Log.w(TAG, "setScreenOrientation: Thread wait failure.");
+            throw new RuntimeException("Unable to change screen orientation.", ex);
+        } finally {
+            LOCK.unlock();
+        }
+    }
+
+    /**
+     * Returns current orientation of the screen.
+     *
+     * @param context the context of the application.
+     * @return returns current screen orientation.
+     */
+    public static ScreenOrientation getScreenOrientation(final Context context) {
+        checkNotNull(context);
+
+        int currentOrientation = context.getResources().getConfiguration().orientation;
+        if (Configuration.ORIENTATION_LANDSCAPE == currentOrientation) {
+            return ScreenOrientation.LANDSCAPE;
+        } else {
+            return ScreenOrientation.PORTRAIT;
+        }
+    }
+}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/FilternatorActivity.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/FilternatorActivity.java
new file mode 100644
index 0000000..1aff03c
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/FilternatorActivity.java
@@ -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.appcompat.app.g3;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+
+import java.util.concurrent.CountDownLatch;
+
+public class FilternatorActivity extends AppCompatActivity {
+    public static CountDownLatch configurationLatch = new CountDownLatch(1);
+    public static Exception configurationException = null;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Configuration initialConfig =
+                new Configuration(getApplication().getResources().getConfiguration());
+        // TODO: If MODE_NIGHT_YES set, expect actualConfig != newConfig in onConfigurationChanged
+        //AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
+
+        super.onCreate(savedInstanceState);
+
+        if (!initialConfig.equals(getApplication().getResources().getConfiguration())) {
+            throw new IllegalStateException("Base configuration got messed up");
+        }
+    }
+
+    @Override
+    public void onConfigurationChanged(@NonNull Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        Configuration actualConfig = getResources().getConfiguration();
+        if (!actualConfig.equals(newConfig)) {
+            int diff = actualConfig.diff(newConfig);
+            configurationException = new RuntimeException("Configuration changes not correctly "
+                    + "reflected in getResources().getConfiguration(), diff is " + diff + ", "
+                    + "actual config is " + actualConfig + ", new config is " + newConfig);
+        }
+
+        if (configurationLatch.getCount() > 0) {
+            configurationLatch.countDown();
+        }
+    }
+}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/FilternatorTest.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/FilternatorTest.kt
new file mode 100644
index 0000000..38d9ab2
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/FilternatorTest.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.appcompat.app.g3
+
+import androidx.appcompat.Orientation
+import androidx.appcompat.withOrientation
+import androidx.lifecycle.Lifecycle
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import androidx.testutils.LifecycleOwnerUtils.waitUntilState
+import androidx.testutils.withActivity
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.TimeUnit
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Regression test for b/235485694, adapted from GmsCore's own tests.
+ */
+@Suppress("SameParameterValue")
+@LargeTest
+@SdkSuppress(minSdkVersion = 18) // UiDevice
+@RunWith(AndroidJUnit4::class)
+class FilternatorTest {
+    @get:Rule
+    val activityRule = ActivityScenarioRule(FilternatorActivity::class.java)
+
+    private lateinit var uiDevice: UiDevice
+
+    @Before
+    fun setup() {
+        uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+    }
+
+    @Test
+    fun testConfigurationUpdatedOnLandscapeMode() {
+        // Wait for the activity to fully start before rotating,
+        // otherwise we won't receive onConfigurationChanged.
+        val activity = activityRule.withActivity { this }
+        waitUntilState(activity, Lifecycle.State.RESUMED)
+
+        // Rotate and wait for the activity to check that
+        // configuration has been properly updated.
+        uiDevice.withOrientation(Orientation.LEFT) {
+            FilternatorActivity.configurationLatch.await(5000, TimeUnit.MILLISECONDS)
+            assertThat(FilternatorActivity.configurationException).isNull()
+        }
+    }
+}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/NavDrawerActivityTest.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/NavDrawerActivityTest.kt
new file mode 100644
index 0000000..c759808
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/NavDrawerActivityTest.kt
@@ -0,0 +1,112 @@
+/*
+ * 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.appcompat.app.g3
+
+import android.content.Intent
+import android.os.Build
+import androidx.appcompat.app.NightModeActivity
+import androidx.appcompat.test.R
+import androidx.lifecycle.Lifecycle
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.Espresso.pressBack
+import androidx.test.espresso.assertion.ViewAssertions.matches
+import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.testutils.LifecycleOwnerUtils.waitUntilState
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Regression test for b/235567649, adapted from Translate's own tests.
+ */
+@SdkSuppress(minSdkVersion = 18)
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class NavDrawerActivityTest {
+    private val context = InstrumentationRegistry.getInstrumentation().targetContext
+
+    @Suppress("DEPRECATION")
+    @get:Rule
+    val activityTestRule = androidx.test.rule.ActivityTestRule(
+        OldTranslateActivity::class.java,
+        /* initialTouchMode = */ false,
+        /* launchActivity = */ false
+    )
+
+    private lateinit var activity: OldTranslateActivity
+    private lateinit var originalScreenOrientation: AndroidTestUtil.ScreenOrientation
+
+    @Before
+    fun setUp() {
+        activity = activityTestRule.launchActivity(null)
+        originalScreenOrientation = AndroidTestUtil.getScreenOrientation(context)
+    }
+
+    @After
+    fun tearDown() {
+        AndroidTestUtil.setScreenOrientation(context, originalScreenOrientation)
+    }
+
+    @Test
+    fun testSettingsBackRotateDevice() {
+        activity.startActivity(
+            Intent(context, NightModeActivity::class.java).apply {
+                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                putExtra(NightModeActivity.KEY_TITLE, "TopActivity")
+            }
+        )
+
+        // Starting activity is hidden, wait for it to stop.
+        waitUntilState(activity, Lifecycle.State.CREATED)
+
+        // Rotate the screen.
+        UITestUtils.rotateScreen(
+            InstrumentationRegistry.getInstrumentation(),
+            originalScreenOrientation
+        )
+
+        // Close the top activity.
+        pressBack()
+
+        // Starting activity is in the foreground, wait for it to resume.
+        waitUntilState(activity, Lifecycle.State.RESUMED)
+
+        assertIsInHomeActivity()
+
+        // press back, make sure that the app exits
+        verifyPressBackAndExitAfterRotation()
+    }
+
+    private fun assertIsInHomeActivity() {
+        onView(withId(R.id.btn_lang_picker_swap)).check(matches(isDisplayed()))
+    }
+
+    private fun verifyPressBackAndExitAfterRotation() {
+        // On 5.1, back button doesn't exit the app, appears to be an emulator quirk.
+        if (Build.VERSION.SDK_INT != Build.VERSION_CODES.LOLLIPOP_MR1) {
+            assertThat(UITestUtils.verifyPressBackAndExit()).isTrue()
+        }
+    }
+}
\ No newline at end of file
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/OldTranslateActivity.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/OldTranslateActivity.java
new file mode 100644
index 0000000..3e554f1
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/OldTranslateActivity.java
@@ -0,0 +1,32 @@
+/*
+ * 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.appcompat.app.g3;
+
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.test.R;
+
+public class OldTranslateActivity extends AppCompatActivity {
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.g3_old_translate_activity);
+    }
+}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/UITestUtils.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/UITestUtils.java
new file mode 100644
index 0000000..3e5c9ac
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/g3/UITestUtils.java
@@ -0,0 +1,51 @@
+/*
+ * 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.appcompat.app.g3;
+
+import static androidx.test.espresso.Espresso.pressBack;
+
+import android.app.Instrumentation;
+
+import androidx.test.espresso.NoActivityResumedException;
+
+/**
+ * Adapted from g3's UITestUtils.java with modifications to pass AndroidX lint.
+ */
+public class UITestUtils {
+    public static void rotateScreen(Instrumentation instrumentation,
+            AndroidTestUtil.ScreenOrientation originalOrientation) {
+        AndroidTestUtil.setScreenOrientation(
+                instrumentation.getTargetContext(),
+                originalOrientation == AndroidTestUtil.ScreenOrientation.PORTRAIT
+                        ? AndroidTestUtil.ScreenOrientation.LANDSCAPE
+                        : AndroidTestUtil.ScreenOrientation.PORTRAIT);
+    }
+
+    /**
+     * Verify that when back button is clicked, the app exits.
+     * @return true if the app exits when back is pressed; false if it did not exit.
+     */
+    public static boolean verifyPressBackAndExit() {
+        try {
+            pressBack();
+        } catch (NoActivityResumedException e) {
+            return true;
+        }
+
+        return false;
+    }
+}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseViewTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseViewTest.java
index 6321a86..83fa83c4 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseViewTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatBaseViewTest.java
@@ -25,6 +25,8 @@
 import static androidx.test.espresso.Espresso.onView;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.testutils.LifecycleOwnerUtils.waitUntilState;
+import static androidx.testutils.PollingCheck.waitFor;
 
 import static org.junit.Assert.assertNull;
 
@@ -44,17 +46,18 @@
 import androidx.appcompat.testutils.TestUtils;
 import androidx.core.content.res.ResourcesCompat;
 import androidx.core.graphics.ColorUtils;
-import androidx.test.espresso.UiController;
+import androidx.lifecycle.Lifecycle;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.rule.ActivityTestRule;
-import androidx.testutils.PollingCheck;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.atomic.AtomicReference;
+
 /**
  * Base class for testing custom view extensions in appcompat-v7 that implement the
  * <code>TintableBackgroundView</code> interface. Extensions of this class run all tests
@@ -65,26 +68,35 @@
 @MediumTest
 public abstract class AppCompatBaseViewTest<A extends BaseTestActivity, T extends View> {
     @Rule
-    public final ActivityTestRule<A> mActivityTestRule;
+    public final ActivityScenarioRule<A> mActivityTestRule;
 
     protected ViewGroup mContainer;
 
     protected A mActivity;
-    protected UiController mUiController;
     protected Resources mResources;
 
     public AppCompatBaseViewTest(Class<A> clazz) {
-        mActivityTestRule = new ActivityTestRule<>(clazz);
+        mActivityTestRule = new ActivityScenarioRule<>(clazz);
     }
 
     @Before
     public void setUp() {
-        mActivity = mActivityTestRule.getActivity();
+        AtomicReference<A> outerActivity = new AtomicReference<>();
+        mActivityTestRule.getScenario().onActivity(outerActivity::set);
+
+        mActivity = outerActivity.get();
         mContainer = mActivity.findViewById(R.id.container);
         mResources = mActivity.getResources();
 
+        // Wait until the Activity is resumed to prevent flakiness.
+        try {
+            waitUntilState(mActivity, Lifecycle.State.RESUMED);
+        } catch (Throwable e) {
+            throw new RuntimeException(e);
+        }
+
         // Wait until the Activity is interactive to prevent flakiness.
-        PollingCheck.waitFor(() -> mActivity.hasWindowFocus());
+        waitFor(() -> mActivity.hasWindowFocus());
     }
 
     /**
@@ -632,8 +644,6 @@
     }
 
     protected void testUntintedBackgroundTintingViewCompatAcrossStateChange(@IdRes int viewId) {
-        final T view = mContainer.findViewById(viewId);
-
         final @ColorInt int oceanDefault = ResourcesCompat.getColor(
                 mResources, R.color.ocean_default, null);
         final @ColorInt int oceanDisabled = ResourcesCompat.getColor(
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatSpinnerRtlTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatSpinnerRtlTest.java
index ba59ede..3ff4329 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatSpinnerRtlTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatSpinnerRtlTest.java
@@ -18,7 +18,6 @@
 import android.app.Instrumentation;
 import android.os.Build;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
 import androidx.test.filters.SdkSuppress;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -50,7 +49,6 @@
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
     }
 
-    @FlakyTest
     @Test
     public void testHorizontalOffsetRtl() {
         AppCompatSpinnerTest.checkOffsetIsCorrect(mInstrumentation, mContainer, 200, false, true);
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatSpinnerTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatSpinnerTest.java
index 7fc0315..822d04e 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatSpinnerTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatSpinnerTest.java
@@ -48,7 +48,6 @@
 import androidx.test.espresso.action.GeneralSwipeAction;
 import androidx.test.espresso.action.Press;
 import androidx.test.espresso.action.Swipe;
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SdkSuppress;
@@ -150,12 +149,11 @@
 
         // Set a different popup background
         spinner.setPopupBackgroundDrawable(ContextCompat.getDrawable(
-                mActivityTestRule.getActivity(), R.drawable.test_background_green));
+                mActivity, R.drawable.test_background_green));
         verifySpinnerPopupTheming(R.id.view_unthemed_popup, R.color.test_green);
     }
 
     @Test
-    @FlakyTest
     public void testThemedPopupRuntimeTheming() {
         final AppCompatSpinner spinner =
                 mContainer.findViewById(R.id.view_ocean_themed_popup);
@@ -167,7 +165,7 @@
 
         // Set a different popup background
         spinner.setPopupBackgroundDrawable(ContextCompat.getDrawable(
-                mActivityTestRule.getActivity(), R.drawable.test_background_blue));
+                mActivity, R.drawable.test_background_blue));
         verifySpinnerPopupTheming(R.id.view_ocean_themed_popup, R.color.test_blue);
     }
 
@@ -188,7 +186,6 @@
     }
 
     @Test
-    @FlakyTest
     public void testSlowScroll() {
         final AppCompatSpinner spinner = mContainer
                 .findViewById(R.id.spinner_dropdown_popup_with_scroll);
@@ -210,7 +207,6 @@
     }
 
     @Test
-    @FlakyTest
     public void testHorizontalOffset() {
         checkOffsetIsCorrect(mInstrumentation, mContainer, 500, false, false);
     }
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatTextViewTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatTextViewTest.java
index 8276a2b..d392322 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatTextViewTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatTextViewTest.java
@@ -53,6 +53,7 @@
 import androidx.annotation.ColorInt;
 import androidx.annotation.ColorRes;
 import androidx.annotation.GuardedBy;
+import androidx.annotation.RequiresApi;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.appcompat.test.R;
 import androidx.appcompat.testutils.TestUtils;
@@ -63,12 +64,12 @@
 import androidx.core.view.ViewCompat;
 import androidx.core.widget.TextViewCompat;
 import androidx.test.annotation.UiThreadTest;
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SdkSuppress;
 import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -116,13 +117,10 @@
         // Emulate delay in kicking off the call to ViewCompat.setBackgroundTintList
         Thread.sleep(200);
         final CountDownLatch latch = new CountDownLatch(1);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TextView view = mActivity.findViewById(R.id.view_untinted_deferred);
-                ViewCompat.setBackgroundTintList(view, oceanColor);
-                latch.countDown();
-            }
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            TextView view = activity.findViewById(R.id.view_untinted_deferred);
+            ViewCompat.setBackgroundTintList(view, oceanColor);
+            latch.countDown();
         });
 
         assertTrue(latch.await(2, TimeUnit.SECONDS));
@@ -579,177 +577,142 @@
     }
 
     @Test
-    @FlakyTest
-    public void testSetTextFuture() throws Throwable {
+    public void testSetTextFuture() {
         final ManualExecutor executor = new ManualExecutor();
 
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                AppCompatTextView tv = mActivity.findViewById(R.id.textview_set_text_async);
-                tv.setText(""); // Make the measured width to be zero.
-                tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
-                        SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), executor));
-            }
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            AppCompatTextView tv = activity.findViewById(R.id.textview_set_text_async);
+            tv.setText(""); // Make the measured width to be zero.
+            tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
+                    SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), executor));
         });
 
         executor.doExecution(0);
 
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                AppCompatTextView tv = mActivity.findViewById(R.id.textview_set_text_async);
-                tv.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            AppCompatTextView tv = activity.findViewById(R.id.textview_set_text_async);
+            tv.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
 
-                // 0 is a initial value of the text view width of this test. setTextFuture should
-                // block and set text inside measure method. So, the result of measurment should not
-                // be zero
-                assertNotEquals(0.0f, tv.getMeasuredWidth());
-                // setText may wrap the given text with SpannedString. Check the contents by casting
-                // to String.
-                assertEquals(SAMPLE_TEXT_1, tv.getText().toString());
-            }
+            // 0 is a initial value of the text view width of this test. setTextFuture should
+            // block and set text inside measure method. So, the result of measurment should not
+            // be zero
+            assertNotEquals(0.0f, tv.getMeasuredWidth());
+            // setText may wrap the given text with SpannedString. Check the contents by casting
+            // to String.
+            assertEquals(SAMPLE_TEXT_1, tv.getText().toString());
         });
     }
 
+    @Ignore // Test blocks forever.
     @Test
-    @FlakyTest
-    public void testSetTextAsync_getTextBlockingTest() throws Throwable {
+    public void testSetTextAsync_getTextBlockingTest() {
         final ManualExecutor executor = new ManualExecutor();
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final AppCompatTextView tv = mActivity.findViewById(R.id.textview_set_text_async);
-                tv.setText(""); // Make the measured width to be zero.
-                tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
-                        SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), executor));
-                tv.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
-                assertNotEquals(0.0f, tv.getMeasuredWidth());
-                assertEquals(SAMPLE_TEXT_1, tv.getText().toString());
-            }
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            final AppCompatTextView tv = activity.findViewById(R.id.textview_set_text_async);
+            tv.setText(""); // Make the measured width to be zero.
+            tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
+                    SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), executor));
+            tv.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
+            assertNotEquals(0.0f, tv.getMeasuredWidth());
+            assertEquals(SAMPLE_TEXT_1, tv.getText().toString());
         });
         executor.doExecution(0);
     }
 
     @Test
-    @FlakyTest
-    public void testSetTextAsync_executionOrder() throws Throwable {
+    public void testSetTextAsync_executionOrder() {
         final ManualExecutor executor = new ManualExecutor();
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final AppCompatTextView tv = mActivity.findViewById(R.id.textview_set_text_async);
-                tv.setText(""); // Make the measured width to be zero.
-                tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
-                        SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), executor));
-                tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
-                        SAMPLE_TEXT_2, tv.getTextMetricsParamsCompat(), executor));
-            }
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            final AppCompatTextView tv = activity.findViewById(R.id.textview_set_text_async);
+            tv.setText(""); // Make the measured width to be zero.
+            tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
+                    SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), executor));
+            tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
+                    SAMPLE_TEXT_2, tv.getTextMetricsParamsCompat(), executor));
         });
         executor.doExecution(1);  // Do execution of 2nd runnable.
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final AppCompatTextView tv = mActivity.findViewById(R.id.textview_set_text_async);
-                tv.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
-                assertNotEquals(0.0f, tv.getMeasuredWidth());
-                // setText may wrap the given text with SpannedString. Check the contents by casting
-                // to String.
-                assertEquals(SAMPLE_TEXT_2, tv.getText().toString());
-            }
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            final AppCompatTextView tv = activity.findViewById(R.id.textview_set_text_async);
+            tv.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
+            assertNotEquals(0.0f, tv.getMeasuredWidth());
+            // setText may wrap the given text with SpannedString. Check the contents by casting
+            // to String.
+            assertEquals(SAMPLE_TEXT_2, tv.getText().toString());
         });
         executor.doExecution(0);  // Do execution of 1st runnable.
         // Even the previous setTextAsync finishes after the next setTextAsync, the last one should
         // be displayed.
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final AppCompatTextView tv = mActivity.findViewById(R.id.textview_set_text_async);
-                // setText may wrap the given text with SpannedString. Check the contents by casting
-                // to String.
-                assertEquals(SAMPLE_TEXT_2, tv.getText().toString());
-            }
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            final AppCompatTextView tv = activity.findViewById(R.id.textview_set_text_async);
+            // setText may wrap the given text with SpannedString. Check the contents by casting
+            // to String.
+            assertEquals(SAMPLE_TEXT_2, tv.getText().toString());
         });
     }
 
     @Test
-    public void testSetTextAsync_directionDifference() throws Throwable {
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.setContentView(R.layout.appcompat_textview_rtl);
-                final ViewGroup container = mActivity.findViewById(R.id.container);
-                final AppCompatTextView tv = mActivity.findViewById(R.id.text_view_rtl);
-                tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
-                        SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), null));
-                container.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
-            }
+    public void testSetTextAsync_directionDifference() {
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            activity.setContentView(R.layout.appcompat_textview_rtl);
+            final ViewGroup container = activity.findViewById(R.id.container);
+            final AppCompatTextView tv = activity.findViewById(R.id.text_view_rtl);
+            tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
+                    SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), null));
+            container.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
         });
     }
 
     @Test
-    public void testSetTextAsync_createAndAttach() throws Throwable {
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.setContentView(R.layout.appcompat_textview_rtl);
-                final ViewGroup container = mActivity.findViewById(R.id.container);
+    public void testSetTextAsync_createAndAttach() {
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            activity.setContentView(R.layout.appcompat_textview_rtl);
+            final ViewGroup container = activity.findViewById(R.id.container);
 
-                final AppCompatTextView tv = new AppCompatTextView(mActivity);
-                tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
-                        SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), null));
-                container.addView(tv);
-                container.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
-            }
+            final AppCompatTextView tv = new AppCompatTextView(activity);
+            tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
+                    SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), null));
+            container.addView(tv);
+            container.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
         });
     }
 
     @Test
-    public void testSetTextAsync_executionOrder_withNull() throws Throwable {
+    public void testSetTextAsync_executionOrder_withNull() {
         final ManualExecutor executor = new ManualExecutor();
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final AppCompatTextView tv = mActivity.findViewById(R.id.textview_set_text_async);
-                tv.setText(""); // Make the measured width to be zero.
-                tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
-                        SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), executor));
-                tv.setTextFuture(null);
-            }
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            final AppCompatTextView tv = activity.findViewById(R.id.textview_set_text_async);
+            tv.setText(""); // Make the measured width to be zero.
+            tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
+                    SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), executor));
+            tv.setTextFuture(null);
         });
         executor.doExecution(0);  // Do execution of 1st runnable.
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final AppCompatTextView tv = mActivity.findViewById(R.id.textview_set_text_async);
-                tv.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
-                // The setTextFuture was reset by passing null.
-                assertEquals(0.0f, tv.getMeasuredWidth(), 0.0f);
-            }
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            final AppCompatTextView tv = activity.findViewById(R.id.textview_set_text_async);
+            tv.measure(UNLIMITED_MEASURE_SPEC, UNLIMITED_MEASURE_SPEC);
+            // The setTextFuture was reset by passing null.
+            assertEquals(0.0f, tv.getMeasuredWidth(), 0.0f);
         });
     }
 
     @Test
-    public void testSetTextAsync_throwExceptionAfterSetTextFuture() throws Throwable {
+    public void testSetTextAsync_throwExceptionAfterSetTextFuture() {
         final ManualExecutor executor = new ManualExecutor();
-        mActivity.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final AppCompatTextView tv = mActivity.findViewById(R.id.textview_set_text_async);
-                tv.setText(""); // Make the measured width to be zero.
-                tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
-                        SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), executor));
-                tv.setTextSize(tv.getTextSize() * 2.0f + 1.0f);
-                executor.doExecution(0);
+        mActivityTestRule.getScenario().onActivity(activity -> {
+            final AppCompatTextView tv = activity.findViewById(R.id.textview_set_text_async);
+            tv.setText(""); // Make the measured width to be zero.
+            tv.setTextFuture(PrecomputedTextCompat.getTextFuture(
+                    SAMPLE_TEXT_1, tv.getTextMetricsParamsCompat(), executor));
+            tv.setTextSize(tv.getTextSize() * 2.0f + 1.0f);
+            executor.doExecution(0);
 
-                // setText may wrap the given text with SpannedString. Check the contents by casting
-                // to String.
-                try {
-                    tv.getText();
-                    fail();
-                } catch (IllegalArgumentException e) {
-                    // pass
-                }
+            // setText may wrap the given text with SpannedString. Check the contents by casting
+            // to String.
+            try {
+                tv.getText();
+                fail();
+            } catch (IllegalArgumentException e) {
+                // pass
             }
         });
     }
@@ -929,7 +892,7 @@
     @SdkSuppress(minSdkVersion = 26)
     @Test
     public void testSetTextClassifier() {
-        final AppCompatTextView textview = new AppCompatTextView(mActivityTestRule.getActivity());
+        final AppCompatTextView textview = new AppCompatTextView(mActivity);
         NoOpTextClassifier noOpTextClassifier = new NoOpTextClassifier();
 
         textview.setTextClassifier(noOpTextClassifier);
@@ -937,6 +900,7 @@
         assertEquals(noOpTextClassifier, textview.getTextClassifier());
     }
 
+    @RequiresApi(26)
     private static class NoOpTextClassifier implements TextClassifier {}
 
     class TestCase {
diff --git a/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_end.xml b/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_end.xml
deleted file mode 100644
index d21ef36..0000000
--- a/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_end.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<!-- Drawer content with two end drawers -->
-<androidx.appcompat.custom.CustomDrawerLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/drawer_layout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <!-- As the main content view, the view below consumes the entire
-         space available using match_parent in both dimensions. Note that
-         this child does not specify android:layout_gravity attribute. -->
-    <FrameLayout
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-    <!-- Start drawer with fixed width. -->
-    <ListView
-        android:id="@+id/end_drawer"
-        android:layout_width="300dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="end"
-        android:background="#333" />
-
-    <!-- Another start drawer with fixed width. -->
-    <FrameLayout
-        android:id="@+id/end_drawer2"
-        android:layout_width="250dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="end"
-        android:background="#444" />
-</androidx.appcompat.custom.CustomDrawerLayout>
-
diff --git a/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_end_single_start.xml b/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_end_single_start.xml
deleted file mode 100644
index 5cc2eaa..0000000
--- a/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_end_single_start.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<!-- Drawer content with two end drawers and one start drawer -->
-<androidx.appcompat.custom.CustomDrawerLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/drawer_layout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <!-- As the main content view, the view below consumes the entire
-         space available using match_parent in both dimensions. Note that
-         this child does not specify android:layout_gravity attribute. -->
-    <FrameLayout
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-    <!-- Start drawer with fixed width. -->
-    <ListView
-        android:id="@+id/end_drawer"
-        android:layout_width="300dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="end"
-        android:background="#333" />
-
-    <!-- Another start drawer with fixed width. -->
-    <FrameLayout
-        android:id="@+id/end_drawer2"
-        android:layout_width="250dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="end"
-        android:background="#444" />
-
-    <!-- Start drawer with fixed width. -->
-    <ListView
-        android:id="@+id/start_drawer"
-        android:layout_width="300dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="start"
-        android:background="#333"
-        android:fitsSystemWindows="true" />
-</androidx.appcompat.custom.CustomDrawerLayout>
-
diff --git a/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_start.xml b/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_start.xml
deleted file mode 100644
index e831c36..0000000
--- a/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_start.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<!-- Drawer content with two start drawers -->
-<androidx.appcompat.custom.CustomDrawerLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/drawer_layout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <!-- As the main content view, the view below consumes the entire
-         space available using match_parent in both dimensions. Note that
-         this child does not specify android:layout_gravity attribute. -->
-    <FrameLayout
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-    <!-- Start drawer with fixed width. -->
-    <ListView
-        android:id="@+id/start_drawer"
-        android:layout_width="300dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="start"
-        android:background="#333"
-        android:fitsSystemWindows="true" />
-
-    <!-- Another start drawer with fixed width. -->
-    <FrameLayout
-        android:id="@+id/start_drawer2"
-        android:layout_width="250dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="start"
-        android:background="#444"
-        android:fitsSystemWindows="true" />
-</androidx.appcompat.custom.CustomDrawerLayout>
-
diff --git a/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_start_single_end.xml b/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_start_single_end.xml
deleted file mode 100644
index e998c31..0000000
--- a/appcompat/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_start_single_end.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<!-- Drawer content with two start drawers and one end drawer -->
-<androidx.appcompat.custom.CustomDrawerLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/drawer_layout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <!-- As the main content view, the view below consumes the entire
-         space available using match_parent in both dimensions. Note that
-         this child does not specify android:layout_gravity attribute. -->
-    <FrameLayout
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-    <!-- Start drawer with fixed width. -->
-    <ListView
-        android:id="@+id/start_drawer"
-        android:layout_width="300dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="start"
-        android:background="#333"
-        android:fitsSystemWindows="true" />
-
-    <!-- Another start drawer with fixed width. -->
-    <FrameLayout
-        android:id="@+id/start_drawer2"
-        android:layout_width="250dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="start"
-        android:background="#444"
-        android:fitsSystemWindows="true" />
-
-    <!-- End drawer with fixed width. -->
-    <ListView
-        android:id="@+id/end_drawer"
-        android:layout_width="300dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="end"
-        android:background="#333" />
-</androidx.appcompat.custom.CustomDrawerLayout>
-
diff --git a/appcompat/appcompat/src/androidTest/res/layout/g3_old_translate_activity.xml b/appcompat/appcompat/src/androidTest/res/layout/g3_old_translate_activity.xml
new file mode 100644
index 0000000..e1e7a0b
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/res/layout/g3_old_translate_activity.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <View
+        android:id="@+id/btn_lang_picker_swap"
+        android:layout_width="100dp"
+        android:layout_height="100dp" />
+
+</LinearLayout>
diff --git a/appsearch/appsearch-builtin-types/api/current.txt b/appsearch/appsearch-builtin-types/api/current.txt
index d971fde..1aacc0b 100644
--- a/appsearch/appsearch-builtin-types/api/current.txt
+++ b/appsearch/appsearch-builtin-types/api/current.txt
@@ -138,6 +138,34 @@
     method public androidx.appsearch.builtintypes.StopwatchLap.Builder setLapNumber(int);
   }
 
+  @androidx.appsearch.annotation.Document(name="builtin:Thing") public final class Thing {
+    method public java.util.List<java.lang.String!> getAlternateNames();
+    method public long getCreationTimestampMillis();
+    method public String? getDescription();
+    method public int getDocumentScore();
+    method public long getDocumentTtlMillis();
+    method public String getId();
+    method public String? getImage();
+    method public String? getName();
+    method public String getNamespace();
+    method public String? getUrl();
+  }
+
+  public static final class Thing.Builder {
+    ctor public Thing.Builder(String, String);
+    ctor public Thing.Builder(androidx.appsearch.builtintypes.Thing);
+    method public androidx.appsearch.builtintypes.Thing.Builder addAlternateName(String);
+    method public androidx.appsearch.builtintypes.Thing build();
+    method public androidx.appsearch.builtintypes.Thing.Builder clearAlternateNames();
+    method public androidx.appsearch.builtintypes.Thing.Builder setCreationTimestampMillis(long);
+    method public androidx.appsearch.builtintypes.Thing.Builder setDescription(String?);
+    method public androidx.appsearch.builtintypes.Thing.Builder setDocumentScore(int);
+    method public androidx.appsearch.builtintypes.Thing.Builder setDocumentTtlMillis(long);
+    method public androidx.appsearch.builtintypes.Thing.Builder setImage(String?);
+    method public androidx.appsearch.builtintypes.Thing.Builder setName(String?);
+    method public androidx.appsearch.builtintypes.Thing.Builder setUrl(String?);
+  }
+
   @androidx.appsearch.annotation.Document(name="builtin:Timer") public final class Timer {
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) public long calculateBaseTimeMillis(android.content.Context);
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) public long calculateCurrentRemainingDurationMillis(android.content.Context);
diff --git a/appsearch/appsearch-builtin-types/api/public_plus_experimental_current.txt b/appsearch/appsearch-builtin-types/api/public_plus_experimental_current.txt
index d971fde..1aacc0b 100644
--- a/appsearch/appsearch-builtin-types/api/public_plus_experimental_current.txt
+++ b/appsearch/appsearch-builtin-types/api/public_plus_experimental_current.txt
@@ -138,6 +138,34 @@
     method public androidx.appsearch.builtintypes.StopwatchLap.Builder setLapNumber(int);
   }
 
+  @androidx.appsearch.annotation.Document(name="builtin:Thing") public final class Thing {
+    method public java.util.List<java.lang.String!> getAlternateNames();
+    method public long getCreationTimestampMillis();
+    method public String? getDescription();
+    method public int getDocumentScore();
+    method public long getDocumentTtlMillis();
+    method public String getId();
+    method public String? getImage();
+    method public String? getName();
+    method public String getNamespace();
+    method public String? getUrl();
+  }
+
+  public static final class Thing.Builder {
+    ctor public Thing.Builder(String, String);
+    ctor public Thing.Builder(androidx.appsearch.builtintypes.Thing);
+    method public androidx.appsearch.builtintypes.Thing.Builder addAlternateName(String);
+    method public androidx.appsearch.builtintypes.Thing build();
+    method public androidx.appsearch.builtintypes.Thing.Builder clearAlternateNames();
+    method public androidx.appsearch.builtintypes.Thing.Builder setCreationTimestampMillis(long);
+    method public androidx.appsearch.builtintypes.Thing.Builder setDescription(String?);
+    method public androidx.appsearch.builtintypes.Thing.Builder setDocumentScore(int);
+    method public androidx.appsearch.builtintypes.Thing.Builder setDocumentTtlMillis(long);
+    method public androidx.appsearch.builtintypes.Thing.Builder setImage(String?);
+    method public androidx.appsearch.builtintypes.Thing.Builder setName(String?);
+    method public androidx.appsearch.builtintypes.Thing.Builder setUrl(String?);
+  }
+
   @androidx.appsearch.annotation.Document(name="builtin:Timer") public final class Timer {
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) public long calculateBaseTimeMillis(android.content.Context);
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) public long calculateCurrentRemainingDurationMillis(android.content.Context);
diff --git a/appsearch/appsearch-builtin-types/api/restricted_current.txt b/appsearch/appsearch-builtin-types/api/restricted_current.txt
index ce72f94..0084b26 100644
--- a/appsearch/appsearch-builtin-types/api/restricted_current.txt
+++ b/appsearch/appsearch-builtin-types/api/restricted_current.txt
@@ -140,6 +140,34 @@
     method public androidx.appsearch.builtintypes.StopwatchLap.Builder setLapNumber(int);
   }
 
+  @androidx.appsearch.annotation.Document(name="builtin:Thing") public final class Thing {
+    method public java.util.List<java.lang.String!> getAlternateNames();
+    method public long getCreationTimestampMillis();
+    method public String? getDescription();
+    method public int getDocumentScore();
+    method public long getDocumentTtlMillis();
+    method public String getId();
+    method public String? getImage();
+    method public String? getName();
+    method public String getNamespace();
+    method public String? getUrl();
+  }
+
+  public static final class Thing.Builder {
+    ctor public Thing.Builder(String, String);
+    ctor public Thing.Builder(androidx.appsearch.builtintypes.Thing);
+    method public androidx.appsearch.builtintypes.Thing.Builder addAlternateName(String);
+    method public androidx.appsearch.builtintypes.Thing build();
+    method public androidx.appsearch.builtintypes.Thing.Builder clearAlternateNames();
+    method public androidx.appsearch.builtintypes.Thing.Builder setCreationTimestampMillis(long);
+    method public androidx.appsearch.builtintypes.Thing.Builder setDescription(String?);
+    method public androidx.appsearch.builtintypes.Thing.Builder setDocumentScore(int);
+    method public androidx.appsearch.builtintypes.Thing.Builder setDocumentTtlMillis(long);
+    method public androidx.appsearch.builtintypes.Thing.Builder setImage(String?);
+    method public androidx.appsearch.builtintypes.Thing.Builder setName(String?);
+    method public androidx.appsearch.builtintypes.Thing.Builder setUrl(String?);
+  }
+
   @androidx.appsearch.annotation.Document(name="builtin:Timer") public final class Timer {
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) public long calculateBaseTimeMillis(android.content.Context);
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) public long calculateCurrentRemainingDurationMillis(android.content.Context);
diff --git a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/ThingTest.java b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/ThingTest.java
new file mode 100644
index 0000000..9093ced
--- /dev/null
+++ b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/ThingTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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.appsearch.builtintypes;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.appsearch.app.GenericDocument;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class ThingTest {
+
+    @Test
+    public void testBuilder() {
+        long now = System.currentTimeMillis();
+        Thing thing = new Thing.Builder("namespace", "thing1")
+                .setDocumentScore(1)
+                .setCreationTimestampMillis(now)
+                .setDocumentTtlMillis(30000)
+                .setName("my first thing")
+                .addAlternateName("my first object")
+                .addAlternateName("माझी पहिली गोष्ट")
+                .setDescription("this is my first schema.org object")
+                .setImage("content://images/thing1")
+                .setUrl("content://things/1")
+                .build();
+
+        assertThat(thing.getNamespace()).isEqualTo("namespace");
+        assertThat(thing.getId()).isEqualTo("thing1");
+        assertThat(thing.getDocumentScore()).isEqualTo(1);
+        assertThat(thing.getCreationTimestampMillis()).isEqualTo(now);
+        assertThat(thing.getDocumentTtlMillis()).isEqualTo(30000);
+        assertThat(thing.getName()).isEqualTo("my first thing");
+        assertThat(thing.getAlternateNames()).isNotNull();
+        assertThat(thing.getAlternateNames())
+                .containsExactly("my first object", "माझी पहिली गोष्ट");
+        assertThat(thing.getDescription()).isEqualTo("this is my first schema.org object");
+        assertThat(thing.getImage()).isEqualTo("content://images/thing1");
+        assertThat(thing.getUrl()).isEqualTo("content://things/1");
+    }
+
+    @Test
+    public void testBuilderCopy_allFieldsAreCopied() {
+        long now = System.currentTimeMillis();
+        Thing thing1 = new Thing.Builder("namespace", "thing1")
+                .setDocumentScore(1)
+                .setCreationTimestampMillis(now)
+                .setDocumentTtlMillis(30000)
+                .setName("my first thing")
+                .addAlternateName("my first object")
+                .addAlternateName("माझी पहिली गोष्ट")
+                .setDescription("this is my first schema.org object")
+                .setImage("content://images/thing1")
+                .setUrl("content://things/1")
+                .build();
+        Thing thing2 = new Thing.Builder(thing1).build();
+
+        assertThat(thing2.getNamespace()).isEqualTo("namespace");
+        assertThat(thing2.getId()).isEqualTo("thing1");
+        assertThat(thing2.getDocumentScore()).isEqualTo(1);
+        assertThat(thing2.getCreationTimestampMillis()).isEqualTo(now);
+        assertThat(thing2.getDocumentTtlMillis()).isEqualTo(30000);
+        assertThat(thing2.getName()).isEqualTo("my first thing");
+        assertThat(thing2.getAlternateNames()).isNotNull();
+        assertThat(thing2.getAlternateNames())
+                .containsExactly("my first object", "माझी पहिली गोष्ट");
+        assertThat(thing2.getDescription()).isEqualTo("this is my first schema.org object");
+        assertThat(thing2.getImage()).isEqualTo("content://images/thing1");
+        assertThat(thing2.getUrl()).isEqualTo("content://things/1");
+    }
+
+    @Test
+    public void testBuilderCopy_copiedFieldsCanBeUpdated() {
+        long now = System.currentTimeMillis();
+        Thing thing1 = new Thing.Builder("namespace", "thing1")
+                .setDocumentScore(1)
+                .setCreationTimestampMillis(now)
+                .setDocumentTtlMillis(30000)
+                .setName("my first thing")
+                .addAlternateName("my first object")
+                .addAlternateName("माझी पहिली गोष्ट")
+                .setDescription("this is my first schema.org object")
+                .setImage("content://images/thing1")
+                .setUrl("content://things/1")
+                .build();
+        Thing thing2 = new Thing.Builder(thing1)
+                .clearAlternateNames()
+                .setImage("content://images/thing2")
+                .setUrl("content://things/2")
+                .build();
+
+        assertThat(thing2.getNamespace()).isEqualTo("namespace");
+        assertThat(thing2.getId()).isEqualTo("thing1");
+        assertThat(thing2.getDocumentScore()).isEqualTo(1);
+        assertThat(thing2.getCreationTimestampMillis()).isEqualTo(now);
+        assertThat(thing2.getDocumentTtlMillis()).isEqualTo(30000);
+        assertThat(thing2.getName()).isEqualTo("my first thing");
+        assertThat(thing2.getAlternateNames()).isEmpty();
+        assertThat(thing2.getDescription()).isEqualTo("this is my first schema.org object");
+        assertThat(thing2.getImage()).isEqualTo("content://images/thing2");
+        assertThat(thing2.getUrl()).isEqualTo("content://things/2");
+    }
+
+    @Test
+    public void testToGenericDocument() throws Exception {
+        long now = System.currentTimeMillis();
+        Thing thing = new Thing.Builder("namespace", "thing1")
+                .setDocumentScore(1)
+                .setCreationTimestampMillis(now)
+                .setDocumentTtlMillis(30000)
+                .setName("my first thing")
+                .addAlternateName("my first object")
+                .addAlternateName("माझी पहिली गोष्ट")
+                .setDescription("this is my first schema.org object")
+                .setImage("content://images/thing1")
+                .setUrl("content://things/1")
+                .build();
+
+        GenericDocument document = GenericDocument.fromDocumentClass(thing);
+        assertThat(document.getSchemaType()).isEqualTo("builtin:Thing");
+        assertThat(document.getNamespace()).isEqualTo("namespace");
+        assertThat(document.getId()).isEqualTo("thing1");
+        assertThat(document.getScore()).isEqualTo(1);
+        assertThat(document.getCreationTimestampMillis()).isEqualTo(now);
+        assertThat(document.getTtlMillis()).isEqualTo(30000);
+        assertThat(document.getPropertyString("name")).isEqualTo("my first thing");
+        assertThat(document.getPropertyStringArray("alternateNames")).isNotNull();
+        assertThat(Arrays.asList(document.getPropertyStringArray("alternateNames")))
+                .containsExactly("my first object", "माझी पहिली गोष्ट");
+        assertThat(document.getPropertyString("description"))
+                .isEqualTo("this is my first schema.org object");
+        assertThat(document.getPropertyString("image")).isEqualTo("content://images/thing1");
+        assertThat(document.getPropertyString("url")).isEqualTo("content://things/1");
+    }
+}
diff --git a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Thing.java b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Thing.java
new file mode 100644
index 0000000..a6be98e
--- /dev/null
+++ b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Thing.java
@@ -0,0 +1,240 @@
+/*
+ * 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.appsearch.builtintypes;
+
+import android.content.Intent;
+import android.net.Uri;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appsearch.annotation.Document;
+import androidx.appsearch.app.AppSearchSchema.StringPropertyConfig;
+import androidx.core.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * AppSearch document representing a <a href="http://schema.org/Thing">Thing</a>, the most generic
+ * type of an item.
+ */
+@Document(name = "builtin:Thing")
+public final class Thing {
+    @Document.Namespace
+    private final String mNamespace;
+
+    @Document.Id
+    private final String mId;
+
+    @Document.Score
+    private final int mDocumentScore;
+
+    @Document.CreationTimestampMillis
+    private final long mCreationTimestampMillis;
+
+    @Document.TtlMillis
+    private final long mDocumentTtlMillis;
+
+    @Document.StringProperty(indexingType = StringPropertyConfig.INDEXING_TYPE_PREFIXES)
+    private final String mName;
+
+    @Document.StringProperty
+    private final List<String> mAlternateNames;
+
+    @Document.StringProperty
+    private final String mDescription;
+
+    @Document.StringProperty
+    private final String mImage;
+
+    @Document.StringProperty
+    private final String mUrl;
+
+    Thing(@NonNull String namespace, @NonNull String id, int documentScore,
+            long creationTimestampMillis, long documentTtlMillis, @Nullable String name,
+            @NonNull List<String> alternateNames, @Nullable String description,
+            @Nullable String image, @Nullable String url) {
+        mNamespace = Preconditions.checkNotNull(namespace);
+        mId = Preconditions.checkNotNull(id);
+        mDocumentScore = documentScore;
+        mCreationTimestampMillis = creationTimestampMillis;
+        mDocumentTtlMillis = documentTtlMillis;
+        mName = name;
+        mAlternateNames = Collections.unmodifiableList(alternateNames);
+        mDescription = description;
+        mImage = image;
+        mUrl = url;
+    }
+
+    /** Returns the namespace (or logical grouping) for this item. */
+    @NonNull
+    public String getNamespace() {
+        return mNamespace;
+    }
+
+    /** Returns the unique identifier for this item. */
+    @NonNull
+    public String getId() {
+        return mId;
+    }
+
+    /** Returns the intrinsic score (or importance) of this item. */
+    public int getDocumentScore() {
+        return mDocumentScore;
+    }
+
+    /** Returns the creation timestamp, in milliseconds since Unix epoch, of this item. */
+    public long getCreationTimestampMillis() {
+        return mCreationTimestampMillis;
+    }
+
+    /**
+     * Returns the time-to-live timestamp, in milliseconds since
+     * {@link #getCreationTimestampMillis()}, for this item.
+     */
+    public long getDocumentTtlMillis() {
+        return mDocumentTtlMillis;
+    }
+
+    /** Returns the name of this item. */
+    @Nullable
+    public String getName() {
+        return mName;
+    }
+
+    /** Returns an unmodifiable list of aliases, if any, for this item. */
+    @NonNull
+    public List<String> getAlternateNames() {
+        return mAlternateNames;
+    }
+
+    /** Returns a description of this item. */
+    @Nullable
+    public String getDescription() {
+        return mDescription;
+    }
+
+    /** Returns the URL for an image of this item. */
+    @Nullable
+    public String getImage() {
+        return mImage;
+    }
+
+    /**
+     * Returns the deeplink URL of this item.
+     *
+     * <p>This item can be opened (or viewed) by creating an {@link Intent#ACTION_VIEW} intent
+     * with this URL as the {@link Intent#setData(Uri)} uri.
+     *
+     * @see <a href="//reference/android/content/Intent#intent-structure">Intent Structure</a>
+     */
+    @Nullable
+    public String getUrl() {
+        return mUrl;
+    }
+
+    /** Builder for {@link Thing}. */
+    public static final class Builder extends BaseBuiltinTypeBuilder<Builder> {
+        private String mName;
+        private List<String> mAlternateNames = new ArrayList<>();
+        private String mDescription;
+        private String mImage;
+        private String mUrl;
+
+        /** Constructs {@link Thing.Builder} with given {@code namespace} and {@code id} */
+        public Builder(@NonNull String namespace, @NonNull String id) {
+            super(namespace, id);
+        }
+
+        /** Constructs {@link Thing.Builder} from existing values in given {@link Thing}. */
+        public Builder(@NonNull Thing thing) {
+            this(thing.getNamespace(), thing.getId());
+            mDocumentScore = thing.getDocumentScore();
+            mCreationTimestampMillis = thing.getCreationTimestampMillis();
+            mDocumentTtlMillis = thing.getDocumentTtlMillis();
+            mName = thing.getName();
+            mAlternateNames = new ArrayList<>(thing.getAlternateNames());
+            mDescription = thing.getDescription();
+            mImage = thing.getImage();
+            mUrl = thing.getUrl();
+        }
+
+        /** Sets the name of the item. */
+        @NonNull
+        public Builder setName(@Nullable String name) {
+            mName = name;
+            return this;
+        }
+
+        /** Adds an alias for the item. */
+        @NonNull
+        public Builder addAlternateName(@NonNull String alternateName) {
+            Preconditions.checkNotNull(alternateName);
+            mAlternateNames.add(alternateName);
+            return this;
+        }
+
+        /** Clears the aliases, if any, for the item. */
+        @NonNull
+        public Builder clearAlternateNames() {
+            mAlternateNames.clear();
+            return this;
+        }
+
+        /** Sets the description for the item. */
+        @NonNull
+        public Builder setDescription(@Nullable String description) {
+            mDescription = description;
+            return this;
+        }
+
+        /** Sets the URL for an image of the item. */
+        @NonNull
+        public Builder setImage(@Nullable String image) {
+            mImage = image;
+            return this;
+        }
+
+        /**
+         * Sets the deeplink URL of the item.
+         *
+         * <p>If this item can be displayed by any system UI surface, or can be read by another
+         * Android package, through one of the
+         * {@link androidx.appsearch.app.SetSchemaRequest.Builder} methods, this {@code url}
+         * should act as a deeplink into the activity that can open it. Callers should be able to
+         * construct an {@link Intent#ACTION_VIEW} intent with the {@code url} as the
+         * {@link Intent#setData(Uri)} to view the item inside your application.
+         *
+         * <p>See <a href="//training/basics/intents/filters">Allowing Other Apps to Start Your
+         * Activity</a> for more details on how to make activities in your app open for use by other
+         * apps by defining intent filters.
+         */
+        @NonNull
+        public Builder setUrl(@Nullable String url) {
+            mUrl = url;
+            return this;
+        }
+
+        /** Builds a {@link Thing} object. */
+        @NonNull
+        public Thing build() {
+            return new Thing(mNamespace, mId, mDocumentScore, mCreationTimestampMillis,
+                    mDocumentTtlMillis, mName, mAlternateNames, mDescription, mImage, mUrl);
+        }
+    }
+}
diff --git a/arch/core/core-common/lint-baseline.xml b/arch/core/core-common/lint-baseline.xml
deleted file mode 100644
index 44db876..0000000
--- a/arch/core/core-common/lint-baseline.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected Entry&lt;K, V> get(K k) {"
-        errorLine2="              ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/internal/FastSafeIterableMap.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Map.Entry&lt;K, V> ceil(K k) {"
-        errorLine2="           ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/internal/FastSafeIterableMap.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected Entry&lt;K, V> get(K k) {"
-        errorLine2="              ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/internal/SafeIterableMap.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Iterator&lt;Map.Entry&lt;K, V>> descendingIterator() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/internal/SafeIterableMap.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public IteratorWithAdditions iteratorWithAdditions() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/internal/SafeIterableMap.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Map.Entry&lt;K, V> eldest() {"
-        errorLine2="           ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/internal/SafeIterableMap.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Map.Entry&lt;K, V> newest() {"
-        errorLine2="           ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/internal/SafeIterableMap.java"/>
-    </issue>
-
-</issues>
diff --git a/arch/core/core-runtime/lint-baseline.xml b/arch/core/core-runtime/lint-baseline.xml
deleted file mode 100644
index e6ab10a..0000000
--- a/arch/core/core-runtime/lint-baseline.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void executeOnDiskIO(Runnable runnable) {"
-        errorLine2="                                ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/executor/ArchTaskExecutor.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void postToMainThread(Runnable runnable) {"
-        errorLine2="                                 ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/executor/ArchTaskExecutor.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void executeOnDiskIO(Runnable runnable) {"
-        errorLine2="                                ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/executor/DefaultTaskExecutor.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void postToMainThread(Runnable runnable) {"
-        errorLine2="                                 ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/executor/DefaultTaskExecutor.java"/>
-    </issue>
-
-</issues>
diff --git a/arch/core/core-testing/lint-baseline.xml b/arch/core/core-testing/lint-baseline.xml
index 893996b..b92baa0 100644
--- a/arch/core/core-testing/lint-baseline.xml
+++ b/arch/core/core-testing/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
@@ -22,15 +22,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void drainTasks(int time, TimeUnit timeUnit)"
-        errorLine2="                                     ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/executor/testing/CountingTaskExecutorRule.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    protected void starting(Description description) {"
         errorLine2="                            ~~~~~~~~~~~">
         <location
@@ -46,58 +37,4 @@
             file="src/main/java/androidx/arch/core/executor/testing/InstantTaskExecutorRule.java"/>
     </issue>
 
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public TaskExecutor getTaskExecutor() {"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/executor/JunitTaskExecutorRule.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Statement apply(final Statement base, Description description) {"
-        errorLine2="           ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/executor/JunitTaskExecutorRule.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Statement apply(final Statement base, Description description) {"
-        errorLine2="                                 ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/executor/JunitTaskExecutorRule.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Statement apply(final Statement base, Description description) {"
-        errorLine2="                                                 ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/executor/JunitTaskExecutorRule.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void executeOnDiskIO(Runnable runnable) {"
-        errorLine2="                                ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/executor/TaskExecutorWithFakeMainThread.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void postToMainThread(Runnable runnable) {"
-        errorLine2="                                 ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/arch/core/executor/TaskExecutorWithFakeMainThread.java"/>
-    </issue>
-
 </issues>
diff --git a/biometric/biometric/lint-baseline.xml b/biometric/biometric/lint-baseline.xml
index c01692f..54800a2 100644
--- a/biometric/biometric/lint-baseline.xml
+++ b/biometric/biometric/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/bluetooth/integration-tests/testapp/src/main/AndroidManifest.xml b/bluetooth/integration-tests/testapp/src/main/AndroidManifest.xml
index c48ff97..f6c02c5 100644
--- a/bluetooth/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/bluetooth/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -22,5 +22,6 @@
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
 
     <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
+    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
 
 </manifest>
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt
index a5d149b..3e27ff9 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/MainActivity.kt
@@ -61,8 +61,9 @@
 
         requestBluetoothPermissions.launch(
             arrayOf(
+                Manifest.permission.ACCESS_FINE_LOCATION,
+                Manifest.permission.BLUETOOTH_ADVERTISE,
                 Manifest.permission.BLUETOOTH_SCAN,
-                Manifest.permission.ACCESS_FINE_LOCATION
             )
         )
     }
diff --git a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/framework/FwkFragment.kt b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/framework/FwkFragment.kt
index 220061d..5261a18 100644
--- a/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/framework/FwkFragment.kt
+++ b/bluetooth/integration-tests/testapp/src/main/java/androidx/bluetooth/integration/testapp/ui/framework/FwkFragment.kt
@@ -18,11 +18,15 @@
 
 import android.annotation.SuppressLint
 import android.bluetooth.BluetoothManager
+import android.bluetooth.le.AdvertiseCallback
+import android.bluetooth.le.AdvertiseData
+import android.bluetooth.le.AdvertiseSettings
 import android.bluetooth.le.ScanCallback
 import android.bluetooth.le.ScanResult
 import android.bluetooth.le.ScanSettings
 import android.content.Context
 import android.os.Bundle
+import android.os.ParcelUuid
 import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
@@ -37,6 +41,7 @@
 
     companion object {
         const val TAG = "FwkFragment"
+        val ServiceUUID: ParcelUuid = ParcelUuid.fromString("0000b81d-0000-1000-8000-00805f9b34fb")
     }
 
     private val scanCallback = object : ScanCallback() {
@@ -53,6 +58,16 @@
         }
     }
 
+    private val advertiseCallback = object : AdvertiseCallback() {
+        override fun onStartFailure(errorCode: Int) {
+            Log.d(TAG, "onStartFailure() called with: errorCode = $errorCode")
+        }
+
+        override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) {
+            Log.d(TAG, "onStartSuccess() called")
+        }
+    }
+
     private var _binding: FragmentFwkBinding? = null
 
     // This property is only valid between onCreateView and onDestroyView.
@@ -77,6 +92,10 @@
         binding.buttonScan.setOnClickListener {
             scan()
         }
+
+        binding.switchAdvertise.setOnClickListener {
+            if (binding.switchAdvertise.isChecked) startAdvertise()
+        }
     }
 
     override fun onDestroyView() {
@@ -105,4 +124,30 @@
         Toast.makeText(context, getString(R.string.scan_start_message), Toast.LENGTH_LONG)
             .show()
     }
+
+    // Permissions are handled by MainActivity requestBluetoothPermissions
+    @SuppressLint("MissingPermission")
+    private fun startAdvertise() {
+        val bluetoothManager =
+            context?.getSystemService(Context.BLUETOOTH_SERVICE) as? BluetoothManager
+
+        val bluetoothAdapter = bluetoothManager?.adapter
+
+        val bleAdvertiser = bluetoothAdapter?.bluetoothLeAdvertiser
+
+        val advertiseSettings = AdvertiseSettings.Builder()
+            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
+            .setTimeout(0)
+            .build()
+
+        val advertiseData = AdvertiseData.Builder()
+            .addServiceUuid(ServiceUUID)
+            .setIncludeDeviceName(true)
+            .build()
+
+        bleAdvertiser?.startAdvertising(advertiseSettings, advertiseData, advertiseCallback)
+
+        Toast.makeText(context, getString(R.string.advertise_start_message), Toast.LENGTH_LONG)
+            .show()
+    }
 }
diff --git a/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_fwk.xml b/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_fwk.xml
index 754f93b..0b9be5f 100644
--- a/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_fwk.xml
+++ b/bluetooth/integration-tests/testapp/src/main/res/layout/fragment_fwk.xml
@@ -34,6 +34,14 @@
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
+    <androidx.appcompat.widget.SwitchCompat
+        android:id="@+id/switch_advertise"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/advertise_using_fwk"
+        app:layout_constraintBottom_toTopOf="@+id/button_scan"
+        app:layout_constraintEnd_toEndOf="parent" />
+
     <Button
         android:id="@+id/button_scan"
         android:layout_width="wrap_content"
diff --git a/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml b/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
index b0142e3..9828cdd 100644
--- a/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
+++ b/bluetooth/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
@@ -29,4 +29,7 @@
 
     <string name="scan_start_message">Scan should have started. Results are in Logcat</string>
     <string name="scan_not_yet_implemented">Scan not yet implemented.</string>
+
+    <string name="advertise_using_fwk">Advertise using Framework Bluetooth APIs</string>
+    <string name="advertise_start_message">Advertise started</string>
 </resources>
diff --git a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/build.gradle b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/build.gradle
index 5ba8226..69da2cb 100644
--- a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/build.gradle
+++ b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/build.gradle
@@ -6,6 +6,10 @@
     id("com.android.library")
 }
 
+android {
+    namespace "androidx.buildSrc.tests.lib"
+}
+
 androidx {
     name = "Sample Library"
     publish = Publish.SNAPSHOT_AND_RELEASE
diff --git a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/src/main/AndroidManifest.xml b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/src/main/AndroidManifest.xml
deleted file mode 100644
index 4a84e24..0000000
--- a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-dep/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright 2020 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.
-  -->
-
-<manifest package="androidx.buildSrc.tests.lib"/>
diff --git a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/build.gradle b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/build.gradle
index 8e04f77..0a06d18 100644
--- a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/build.gradle
+++ b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/build.gradle
@@ -9,6 +9,10 @@
     implementation("androidx.buildSrc-tests:buildSrc-tests-max-dep-versions-dep:1.0.0")
 }
 
+android {
+    namespace "androidx.testapp"
+}
+
 androidx {
     name = "Sample Dependent library"
     mavenGroup = LibraryGroups.BUILDSRC_TESTS
diff --git a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/src/main/AndroidManifest.xml b/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/src/main/AndroidManifest.xml
deleted file mode 100644
index e52ac12..0000000
--- a/buildSrc-tests/max-dep-versions/buildSrc-tests-max-dep-versions-main/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright 2020 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.
-  -->
-
-<manifest package="androidx.testapp"/>
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index 99be1fd..a211ad0 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -256,7 +256,7 @@
                 )
             task.systemProperty(
                 "robolectric.dependency.dir",
-                robolectricDependencies.absolutePath
+                robolectricDependencies.relativeTo(project.projectDir)
             )
         }
     }
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRootImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRootImplPlugin.kt
index 492b593..b8e1f4f 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRootImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXRootImplPlugin.kt
@@ -40,6 +40,7 @@
 import org.gradle.api.tasks.bundling.ZipEntryCompression
 import org.gradle.build.event.BuildEventsListenerRegistry
 import org.gradle.kotlin.dsl.extra
+import org.jetbrains.kotlin.gradle.plugin.sources.CleanupStaleSourceSetMetadataEntriesService
 
 abstract class AndroidXRootImplPlugin : Plugin<Project> {
     @Suppress("UnstableApiUsage")
@@ -56,6 +57,7 @@
     private fun Project.configureRootProject() {
         project.validateAllAndroidxArgumentsAreRecognized()
         tasks.register("listAndroidXProperties", ListAndroidXPropertiesTask::class.java)
+        this.disableKmpKlibCleanupService()
         setDependencyVersions()
         configureKtlintCheckFile()
         tasks.register(CheckExternalDependencyLicensesTask.TASK_NAME)
@@ -236,4 +238,35 @@
         androidx.build.dependencies.agpVersion = getVersionByName("androidGradlePlugin")
         androidx.build.dependencies.guavaVersion = getVersionByName("guavaJre")
     }
+
+    /**
+     * This function applies the workaround for b/236850628.
+     * There is a BuildService in KMP Gradle Plugin 1.7.0 that tries to cleanup unused klibs,
+     * which is over-eager and causes missing dependencies in the Studio UI. This function simply
+     * breaks the inputs of that cleanup function by intercepting the service creation and changing
+     * its parameters.
+     *
+     * That code is already removed in KMP main branch and we should be able to remove this
+     * workaround after updating to 1.7.20.
+     *
+     * see b/236850628#comment25 for more details.
+     */
+    private fun Project.disableKmpKlibCleanupService() {
+        project.gradle.sharedServices.registrations.whenObjectAdded { serviceRegistration ->
+            if (serviceRegistration.name == "cleanup-stale-sourceset-metadata") {
+                val params = serviceRegistration.parameters as
+                    CleanupStaleSourceSetMetadataEntriesService.Parameters
+                val tmpDirectory = project.layout.buildDirectory.dir("klib-cleanup-workaround")
+                params.projectStorageRoot.set(
+                    tmpDirectory.map { it.asFile }
+                )
+                params.projectStorageDirectories.set(emptyMap())
+                // make sure the store root is not changed afterwards. we don't need to set this
+                // for projectStorageDirectories as the files are deleted from projectStorageRoot,
+                // not projectStorageDirectories.
+                // https://github.com/JetBrains/kotlin/blob/47beef16f38ea315bf4d7d4d3faf34b0b952b613/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/SourceSetMetadataStorageForIde.kt#L26
+                params.projectStorageRoot.disallowChanges()
+            }
+        }
+    }
 }
diff --git a/buildSrc/remoteBuildCache.gradle b/buildSrc/remoteBuildCache.gradle
deleted file mode 100644
index 3e96865..0000000
--- a/buildSrc/remoteBuildCache.gradle
+++ /dev/null
@@ -1,65 +0,0 @@
-import androidx.build.gradle.gcpbuildcache.GcpBuildCache
-import androidx.build.gradle.gcpbuildcache.GcpBuildCacheServiceFactory
-
-buildscript {
-    ext.supportRootFolder = buildscript.sourceFile.getParentFile().getParentFile()
-    apply(from: "repos.gradle")
-    repos.addMavenRepositories(repositories)
-
-    dependencies {
-        classpath("androidx.build.gradle.gcpbuildcache:gcpbuildcache:1.0.0-alpha05")
-    }
-}
-
-def cacheSetting = System.getenv("USE_ANDROIDX_REMOTE_BUILD_CACHE")
-def BUILD_NUMBER = System.getenv("BUILD_NUMBER")
-
-switch (cacheSetting) {
-    case "true":
-    case "uplink": // legacy build cache
-        gradle.settingsEvaluated { settings ->
-            settings.buildCache {
-                remote(HttpBuildCache) {
-                    def osName = System.getProperty("os.name").toLowerCase()
-                    switch (osName) {
-                        case { it.contains("mac os x") }:
-                        case { it.contains("darwin") }:
-                        case { it.contains("osx") }:
-                            url = "http://gradle-remote-cache.uplink2.goog:999/cache/"
-                            break
-                        default:
-                            url = "http://gradle-remote-cache.uplink.goog:999/cache/"
-                            break
-                    }
-                    allowInsecureProtocol = true
-                    push = true
-                }
-            }
-        }
-        break
-    case "gcp":
-        gradle.settingsEvaluated { settings ->
-            buildCache {
-              registerBuildCacheService(GcpBuildCache, GcpBuildCacheServiceFactory)
-            }
-
-            settings.buildCache {
-                remote(GcpBuildCache) {
-                    projectId = "androidx-ge"
-                    bucketName = "androidx-gradle-remote-cache"
-                    push = (BUILD_NUMBER != null && !BUILD_NUMBER.startsWith("P"))
-                }
-            }
-        }
-        break
-    case "false":
-        break
-    default:
-        def uplinkLinux = new File("/usr/bin/uplink-helper")
-        def uplinkMac = new File("/usr/local/bin/uplink-helper")
-        if (uplinkLinux.exists() || uplinkMac.exists()) {
-            logger.warn("\u001B[31m\nIt looks like you are a Googler running without remote build "
-                    + "cache. Enable it for faster builds, see " +
-                    "http://go/androidx-dev#remote-build-cache\u001B[0m\n")
-        }
-}
diff --git a/camera/camera-camera2/lint-baseline.xml b/camera/camera-camera2/lint-baseline.xml
index c696b13..8b2b44e 100644
--- a/camera/camera-camera2/lint-baseline.xml
+++ b/camera/camera-camera2/lint-baseline.xml
@@ -1,49 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="UnsafeOptInUsageError"
-        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.camera.core.ExperimentalZeroShutterLag&apos; or &apos;@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)&apos;"
-        errorLine1="    public boolean isZslSupported() {"
-        errorLine2="                   ~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java"
-            line="358"
-            column="20"/>
-    </issue>
-
-    <issue
-        id="UnsafeOptInUsageError"
-        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.camera.core.ExperimentalZeroShutterLag&apos; or &apos;@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)&apos;"
-        errorLine1="        return Build.VERSION.SDK_INT >= 23"
-        errorLine2="               ^">
-        <location
-            file="src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java"
-            line="359"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnsafeOptInUsageError"
-        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.camera.core.ExperimentalZeroShutterLag&apos; or &apos;@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)&apos;"
-        errorLine1="                        captureMode == ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG"
-        errorLine2="                                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/camera2/internal/Camera2UseCaseConfigFactory.java"
-            line="69"
-            column="53"/>
-    </issue>
-
-    <issue
-        id="UnsafeOptInUsageError"
-        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.camera.core.ExperimentalZeroShutterLag&apos; or &apos;@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)&apos;"
-        errorLine1="                        captureMode == ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG"
-        errorLine2="                                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/camera2/internal/Camera2UseCaseConfigFactory.java"
-            line="97"
-            column="53"/>
-    </issue>
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
@@ -137,29 +93,38 @@
 
     <issue
         id="UnsafeOptInUsageError"
-        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.camera.camera2.interop.ExperimentalCamera2Interop&apos; or &apos;@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)&apos;"
-        errorLine1="            builder.setCaptureRequestOption(CaptureRequest.SCALER_CROP_REGION,"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~">
+        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.camera.core.ExperimentalZeroShutterLag&apos; or &apos;@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)&apos;"
+        errorLine1="    public boolean isZslSupported() {"
+        errorLine2="                   ~~~~~~~~~~~~~~">
         <location
-            file="src/main/java/androidx/camera/camera2/internal/CropRegionZoomImpl.java"/>
+            file="src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java"/>
     </issue>
 
     <issue
         id="UnsafeOptInUsageError"
-        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.camera.camera2.interop.ExperimentalCamera2Interop&apos; or &apos;@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)&apos;"
-        errorLine1="            builder.setCaptureRequestOption(CaptureRequest.SCALER_CROP_REGION,"
-        errorLine2="                                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.camera.core.ExperimentalZeroShutterLag&apos; or &apos;@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)&apos;"
+        errorLine1="        return Build.VERSION.SDK_INT >= 23 &amp;&amp; isPrivateReprocessingSupported();"
+        errorLine2="               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="src/main/java/androidx/camera/camera2/internal/CropRegionZoomImpl.java"/>
+            file="src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java"/>
     </issue>
 
     <issue
         id="UnsafeOptInUsageError"
-        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.camera.camera2.interop.ExperimentalCamera2Interop&apos; or &apos;@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)&apos;"
-        errorLine1="                    mCurrentCropRect);"
-        errorLine2="                    ~~~~~~~~~~~~~~~~">
+        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.camera.core.ExperimentalZeroShutterLag&apos; or &apos;@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)&apos;"
+        errorLine1="                        captureMode == ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG"
+        errorLine2="                                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="src/main/java/androidx/camera/camera2/internal/CropRegionZoomImpl.java"/>
+            file="src/main/java/androidx/camera/camera2/internal/Camera2UseCaseConfigFactory.java"/>
+    </issue>
+
+    <issue
+        id="UnsafeOptInUsageError"
+        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.camera.core.ExperimentalZeroShutterLag&apos; or &apos;@OptIn(markerClass = androidx.camera.core.ExperimentalZeroShutterLag.class)&apos;"
+        errorLine1="                        captureMode == ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG"
+        errorLine2="                                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="src/main/java/androidx/camera/camera2/internal/Camera2UseCaseConfigFactory.java"/>
     </issue>
 
     <issue
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 fc6153b..6839558 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
@@ -75,10 +75,12 @@
 import androidx.camera.core.impl.MutableOptionsBundle;
 import androidx.camera.core.impl.Quirks;
 import androidx.camera.core.impl.SessionConfig;
+import androidx.camera.core.impl.UseCaseConfig;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.impl.utils.futures.FutureCallback;
 import androidx.camera.core.impl.utils.futures.Futures;
 import androidx.camera.testing.CameraUtil;
+import androidx.camera.testing.fakes.FakeUseCaseConfig;
 import androidx.concurrent.futures.CallbackToFutureAdapter;
 import androidx.core.os.HandlerCompat;
 import androidx.test.core.app.ApplicationProvider;
@@ -103,6 +105,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -231,7 +234,7 @@
         FutureCallback<Void> mockFutureCallback = mock(FutureCallback.class);
 
         Futures.addCallback(captureSession.open(mTestParameters0.mSessionConfig,
-                mCameraDeviceHolder.get(), mCaptureSessionOpenerBuilder.build()),
+                        mCameraDeviceHolder.get(), mCaptureSessionOpenerBuilder.build()),
                 mockFutureCallback, CameraXExecutors.mainThreadExecutor());
 
         assertTrue(mTestParameters0.waitForData());
@@ -277,6 +280,16 @@
                 == OutputConfigurationCompat.STREAM_USE_CASE_NONE);
     }
 
+    @SdkSuppress(maxSdkVersion = 32)
+    @Test
+    public void getStreamUseCaseFromUseCaseConfigsNotSupported() {
+        Collection<UseCaseConfig<?>> useCaseConfigs = new ArrayList<>();
+        useCaseConfigs.add(new FakeUseCaseConfig.Builder().getUseCaseConfig());
+        assertTrue(StreamUseCaseUtil.getStreamUseCaseFromUseCaseConfigs(useCaseConfigs,
+                new ArrayList<>())
+                == OutputConfigurationCompat.STREAM_USE_CASE_NONE);
+    }
+
     // Sharing surface of YUV format is supported since API 28
     @SdkSuppress(minSdkVersion = 28)
     @Test
@@ -445,7 +458,7 @@
         FutureCallback<Void> mockFutureCallback = mock(FutureCallback.class);
 
         Futures.addCallback(captureSession.open(mTestParameters0.mSessionConfig,
-                mCameraDeviceHolder.get(), mCaptureSessionOpenerBuilder.build()),
+                        mCameraDeviceHolder.get(), mCaptureSessionOpenerBuilder.build()),
                 mockFutureCallback, CameraXExecutors.mainThreadExecutor());
 
         verify(mockFutureCallback, timeout(3000)).onFailure(any(Throwable.class));
@@ -463,7 +476,7 @@
         FutureCallback<Void> mockFutureCallback = mock(FutureCallback.class);
 
         Futures.addCallback(captureSession.open(mTestParameters0.mSessionConfig,
-                mCameraDeviceHolder.get(), mCaptureSessionOpenerBuilder.build()),
+                        mCameraDeviceHolder.get(), mCaptureSessionOpenerBuilder.build()),
                 mockFutureCallback, CameraXExecutors.mainThreadExecutor());
 
         verify(mockFutureCallback, timeout(3000)).onSuccess(any());
@@ -539,7 +552,7 @@
         captureSession.setSessionConfig(parameters.mSessionConfig);
         FutureCallback<Void> mockFutureCallback = mock(FutureCallback.class);
         Futures.addCallback(captureSession.open(parameters.mSessionConfig,
-                mCameraDeviceHolder.get(), mCaptureSessionOpenerBuilder.build()),
+                        mCameraDeviceHolder.get(), mCaptureSessionOpenerBuilder.build()),
                 mockFutureCallback, CameraXExecutors.mainThreadExecutor());
 
         verify(mockFutureCallback, timeout(waitTimeout)).onSuccess(any());
@@ -1053,7 +1066,7 @@
         ArgumentCaptor<Throwable> throwableCaptor = ArgumentCaptor.forClass(Throwable.class);
 
         Futures.addCallback(captureSession.open(mTestParameters0.mSessionConfig,
-                mCameraDeviceHolder.get(), mCaptureSessionOpenerBuilder.build()),
+                        mCameraDeviceHolder.get(), mCaptureSessionOpenerBuilder.build()),
                 mockFutureCallback, CameraXExecutors.mainThreadExecutor());
 
         verify(mockFutureCallback, timeout(3000).times(1)).onFailure(throwableCaptor.capture());
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java
index d504a72..1faf17e 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraControlImpl.java
@@ -481,9 +481,10 @@
         // completed. On some devices, AE precapture triggered in submitStillCaptures may not
         // work properly if the repeating request to change the flash mode is not completed.
         int flashMode = getFlashMode();
-        return FutureChain.from(mFlashModeChangeSessionUpdateFuture).transformAsync(
-                v -> mCamera2CapturePipeline.submitStillCaptures(
-                        captureConfigs, captureMode, flashMode, flashType), mExecutor);
+        return FutureChain.from(Futures.nonCancellationPropagating(
+                mFlashModeChangeSessionUpdateFuture)).transformAsync(
+                    v -> mCamera2CapturePipeline.submitStillCaptures(captureConfigs, captureMode,
+                        flashMode, flashType), mExecutor);
     }
 
     /** {@inheritDoc} */
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
index a72ac3f..4132879 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraImpl.java
@@ -1122,6 +1122,9 @@
             debugLog("Unable to create capture session due to conflicting configurations");
             return;
         }
+        validatingBuilder.setStreamUseCase(StreamUseCaseUtil.getStreamUseCaseFromUseCaseConfigs(
+                mUseCaseAttachState.getAttachedUseCaseConfigs(),
+                mUseCaseAttachState.getAttachedSessionConfigs()));
 
         CaptureSessionInterface captureSession = mCaptureSession;
         ListenableFuture<Void> openCaptureSession = captureSession.open(validatingBuilder.build(),
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java
index 1c30ac5..82f57d0 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CaptureSession.java
@@ -314,6 +314,7 @@
                                         outputConfig,
                                         mConfiguredSurfaceMap,
                                         physicalCameraIdForAllStreams);
+                        outputConfiguration.setStreamUseCase(sessionConfig.getStreamUseCase());
                         outputConfigList.add(outputConfiguration);
                     }
 
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CropRegionZoomImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CropRegionZoomImpl.java
index 4ec3c82..812a230 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CropRegionZoomImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/CropRegionZoomImpl.java
@@ -22,9 +22,11 @@
 import android.hardware.camera2.TotalCaptureResult;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.OptIn;
 import androidx.annotation.RequiresApi;
 import androidx.camera.camera2.impl.Camera2ImplConfig;
 import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
+import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
 import androidx.camera.core.CameraControl;
 import androidx.concurrent.futures.CallbackToFutureAdapter;
 import androidx.core.util.Preconditions;
@@ -61,11 +63,11 @@
         return maxZoom;
     }
 
+    @OptIn(markerClass = ExperimentalCamera2Interop.class)
     @Override
     public void addRequestOption(@NonNull Camera2ImplConfig.Builder builder) {
         if (mCurrentCropRect != null) {
-            builder.setCaptureRequestOption(CaptureRequest.SCALER_CROP_REGION,
-                    mCurrentCropRect);
+            builder.setCaptureRequestOption(CaptureRequest.SCALER_CROP_REGION, mCurrentCropRect);
         }
     }
 
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ExposureControl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ExposureControl.java
index dcc344d..0dd44c2 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ExposureControl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/ExposureControl.java
@@ -23,10 +23,12 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
 import androidx.annotation.RequiresApi;
 import androidx.camera.camera2.impl.Camera2ImplConfig;
 import androidx.camera.camera2.internal.annotation.CameraExecutor;
 import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
+import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
 import androidx.camera.core.CameraControl;
 import androidx.camera.core.ExposureState;
 import androidx.camera.core.impl.annotation.ExecutedBy;
@@ -125,6 +127,7 @@
      * to the shared options. It applies to all repeating requests and single requests.
      */
     @ExecutedBy("mExecutor")
+    @OptIn(markerClass = ExperimentalCamera2Interop.class)
     void setCaptureRequestOption(@NonNull Camera2ImplConfig.Builder configBuilder) {
         configBuilder.setCaptureRequestOption(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,
                 mExposureStateImpl.getExposureCompensationIndex());
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/StreamUseCaseUtil.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/StreamUseCaseUtil.java
new file mode 100644
index 0000000..4e50b76
--- /dev/null
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/StreamUseCaseUtil.java
@@ -0,0 +1,130 @@
+/*
+ * 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.camera.camera2.internal;
+
+import android.hardware.camera2.CameraDevice;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.camera.camera2.internal.compat.params.OutputConfigurationCompat;
+import androidx.camera.core.impl.ImageAnalysisConfig;
+import androidx.camera.core.impl.ImageCaptureConfig;
+import androidx.camera.core.impl.PreviewConfig;
+import androidx.camera.core.impl.SessionConfig;
+import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.VideoCaptureConfig;
+
+import java.util.Collection;
+
+/**
+ * A class that contains utility methods for stream use case.
+ */
+public final class StreamUseCaseUtil {
+
+    private StreamUseCaseUtil() {
+    }
+
+    /**
+     * Returns the appropriate stream use case for a capture session based on the attached
+     * CameraX use cases. If API level is below 33, return
+     * {@value OutputConfigurationCompat#STREAM_USE_CASE_NONE}. If use cases are empty or is ZSL,
+     * return DEFAULT. Otherwise, return PREVIEW_VIDEO_STILL for ImageCapture + VideoCapture;
+     * return STILL_CAPTURE for ImageCapture; return VIDEO_RECORD for VideoCapture; return
+     * VIEW_FINDER for Preview only.
+     *
+     * @param useCaseConfigs collection of all attached CameraX use cases for this capture session
+     * @param sessionConfigs collection of all session configs for this capture session
+     * @return the appropriate stream use case for this capture session
+     */
+    public static long getStreamUseCaseFromUseCaseConfigs(
+            @NonNull Collection<UseCaseConfig<?>> useCaseConfigs,
+            @NonNull Collection<SessionConfig> sessionConfigs) {
+        if (Build.VERSION.SDK_INT < 33) {
+            return OutputConfigurationCompat.STREAM_USE_CASE_NONE;
+        }
+        if (useCaseConfigs.isEmpty()) {
+            //If the collection is empty, return default case.
+            //TODO: b/237337336 Return SCALER_AVAILABLE_STREAM_USE_CASE_DEFAULT here
+            return OutputConfigurationCompat.STREAM_USE_CASE_NONE;
+        } else {
+            for (SessionConfig sessionConfig : sessionConfigs) {
+                if (sessionConfig.getTemplateType() == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG) {
+                    //If is ZSL, return default case.
+                    //TODO: b/237337336 Return SCALER_AVAILABLE_STREAM_USE_CASE_DEFAULT here
+                    return OutputConfigurationCompat.STREAM_USE_CASE_NONE;
+                }
+            }
+            boolean hasImageCapture = false, hasVideoCapture = false, hasPreview = false;
+            for (UseCaseConfig<?> useCaseConfig : useCaseConfigs) {
+                if (useCaseConfig instanceof ImageAnalysisConfig) {
+                    //If contains analysis use case, return default case.
+                    //TODO: b/237337336 Return SCALER_AVAILABLE_STREAM_USE_CASE_DEFAULT here
+                    return OutputConfigurationCompat.STREAM_USE_CASE_NONE;
+                }
+
+                if (useCaseConfig instanceof PreviewConfig) {
+                    hasPreview = true;
+                    continue;
+                }
+
+                if (useCaseConfig instanceof ImageCaptureConfig) {
+                    if (hasVideoCapture) {
+                        // If has both image and video capture, return preview video still case.
+                        //TODO: b/237337336 Return
+                        // SCALER_AVAILABLE_STREAM_USE_CASE_PREVIEW_VIDEO_STILL here
+                        return OutputConfigurationCompat.STREAM_USE_CASE_NONE;
+                    }
+                    hasImageCapture = true;
+                    continue;
+
+                }
+
+                if (useCaseConfig instanceof VideoCaptureConfig) {
+                    if (hasImageCapture) {
+                        // If has both image and video capture, return preview video still case.
+                        //TODO: b/237337336 Return
+                        // SCALER_AVAILABLE_STREAM_USE_CASE_PREVIEW_VIDEO_STILL here
+                        return OutputConfigurationCompat.STREAM_USE_CASE_NONE;
+                    }
+                    hasVideoCapture = true;
+                    continue;
+
+                }
+            }
+            if (!hasPreview) {
+                // If doesn't contain preview, we are not sure what's the situation. Return
+                // default case.
+                //TODO: b/237337336 Return SCALER_AVAILABLE_STREAM_USE_CASE_DEFAULT here
+                return OutputConfigurationCompat.STREAM_USE_CASE_NONE;
+            }
+
+            if (hasImageCapture) {
+                // If contains image capture, return still capture case.
+                //TODO: b/237337336 Return SCALER_AVAILABLE_STREAM_USE_CASE_STILL_CAPTURE here
+                return OutputConfigurationCompat.STREAM_USE_CASE_NONE;
+            } else if (hasVideoCapture) {
+                // If contains video capture, return video record case.
+                //TODO: b/237337336 Return SCALER_AVAILABLE_STREAM_USE_CASE_VIDEO_RECORD here
+                return OutputConfigurationCompat.STREAM_USE_CASE_NONE;
+            } else {
+                // If contains only preview, return view finder case.
+                //TODO: b/237337336 Return SCALER_AVAILABLE_STREAM_USE_CASE_VIEW_FINDER here
+                return OutputConfigurationCompat.STREAM_USE_CASE_NONE;
+            }
+        }
+    }
+}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/ImageCapturePixelHDRPlus.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/ImageCapturePixelHDRPlus.java
index 7334bfb..2067ca8 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/ImageCapturePixelHDRPlus.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/ImageCapturePixelHDRPlus.java
@@ -20,10 +20,12 @@
 import android.hardware.camera2.CaptureRequest;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.OptIn;
 import androidx.annotation.RequiresApi;
 import androidx.camera.camera2.impl.Camera2ImplConfig;
 import androidx.camera.camera2.internal.compat.quirk.DeviceQuirks;
 import androidx.camera.camera2.internal.compat.quirk.ImageCapturePixelHDRPlusQuirk;
+import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
 import androidx.camera.core.ImageCapture;
 
 /**
@@ -31,6 +33,7 @@
  *
  * @see ImageCapturePixelHDRPlusQuirk
  */
+@OptIn(markerClass = ExperimentalCamera2Interop.class)
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public class ImageCapturePixelHDRPlus {
 
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/PreviewPixelHDRnet.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/PreviewPixelHDRnet.java
index 6a001a8..0465d6d 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/PreviewPixelHDRnet.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/PreviewPixelHDRnet.java
@@ -19,10 +19,12 @@
 import android.hardware.camera2.CaptureRequest;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.OptIn;
 import androidx.annotation.RequiresApi;
 import androidx.camera.camera2.impl.Camera2ImplConfig;
 import androidx.camera.camera2.internal.compat.quirk.DeviceQuirks;
 import androidx.camera.camera2.internal.compat.quirk.PreviewPixelHDRnetQuirk;
+import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
 import androidx.camera.core.impl.SessionConfig;
 
 /**
@@ -39,6 +41,7 @@
     /**
      * Turns on WYSIWYG viewfinder on Pixel devices
      */
+    @OptIn(markerClass = ExperimentalCamera2Interop.class)
     public static void setHDRnet(@NonNull SessionConfig.Builder sessionBuilder) {
         final PreviewPixelHDRnetQuirk quirk = DeviceQuirks.get(PreviewPixelHDRnetQuirk.class);
         if (quirk == null) {
diff --git a/camera/camera-core/api/current.txt b/camera/camera-core/api/current.txt
index e0cfba8..9aaeb6b 100644
--- a/camera/camera-core/api/current.txt
+++ b/camera/camera-core/api/current.txt
@@ -193,8 +193,8 @@
 
   public static interface ImageAnalysis.Analyzer {
     method public void analyze(androidx.camera.core.ImageProxy);
+    method public default android.util.Size? getDefaultTargetResolution();
     method public default int getTargetCoordinateSystem();
-    method public default android.util.Size? getTargetResolutionOverride();
     method public default void updateTransform(android.graphics.Matrix?);
   }
 
diff --git a/camera/camera-core/api/public_plus_experimental_current.txt b/camera/camera-core/api/public_plus_experimental_current.txt
index 67ac528..613a450 100644
--- a/camera/camera-core/api/public_plus_experimental_current.txt
+++ b/camera/camera-core/api/public_plus_experimental_current.txt
@@ -204,8 +204,8 @@
 
   public static interface ImageAnalysis.Analyzer {
     method public void analyze(androidx.camera.core.ImageProxy);
+    method public default android.util.Size? getDefaultTargetResolution();
     method public default int getTargetCoordinateSystem();
-    method public default android.util.Size? getTargetResolutionOverride();
     method public default void updateTransform(android.graphics.Matrix?);
   }
 
diff --git a/camera/camera-core/api/restricted_current.txt b/camera/camera-core/api/restricted_current.txt
index e0cfba8..9aaeb6b 100644
--- a/camera/camera-core/api/restricted_current.txt
+++ b/camera/camera-core/api/restricted_current.txt
@@ -193,8 +193,8 @@
 
   public static interface ImageAnalysis.Analyzer {
     method public void analyze(androidx.camera.core.ImageProxy);
+    method public default android.util.Size? getDefaultTargetResolution();
     method public default int getTargetCoordinateSystem();
-    method public default android.util.Size? getTargetResolutionOverride();
     method public default void updateTransform(android.graphics.Matrix?);
   }
 
diff --git a/camera/camera-core/build.gradle b/camera/camera-core/build.gradle
index c11aab9..a266a1e 100644
--- a/camera/camera-core/build.gradle
+++ b/camera/camera-core/build.gradle
@@ -34,6 +34,7 @@
     implementation("androidx.concurrent:concurrent-futures:1.0.0")
     implementation("androidx.lifecycle:lifecycle-common:2.1.0")
     implementation(libs.autoValueAnnotations)
+    androidTestImplementation project(path: ':camera:camera-camera2')
     compileOnly(project(":external:libyuv"))
 
     annotationProcessor(libs.autoValue)
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/SessionConfigTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/SessionConfigTest.java
index 38b2fd2..b283a24 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/SessionConfigTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/SessionConfigTest.java
@@ -26,6 +26,7 @@
 import android.hardware.camera2.CameraDevice;
 import android.view.Surface;
 
+import androidx.camera.camera2.internal.compat.params.OutputConfigurationCompat;
 import androidx.camera.core.ImageCapture;
 import androidx.camera.core.Preview;
 import androidx.camera.core.VideoCapture;
@@ -284,6 +285,15 @@
     }
 
     @Test
+    public void setStreamUseCase() {
+        SessionConfig.ValidatingBuilder validatingBuilder = new SessionConfig.ValidatingBuilder();
+        assertThat(validatingBuilder.build().getStreamUseCase()
+                == OutputConfigurationCompat.STREAM_USE_CASE_NONE);
+        validatingBuilder.setStreamUseCase(1);
+        assertThat(validatingBuilder.build().getStreamUseCase() == 1);
+    }
+
+    @Test
     public void conflictingOptions() {
         SessionConfig.Builder builder0 = new SessionConfig.Builder();
         MutableOptionsBundle options0 = MutableOptionsBundle.create();
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceEffectTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceEffectTest.kt
new file mode 100644
index 0000000..0a214ed
--- /dev/null
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/DefaultSurfaceEffectTest.kt
@@ -0,0 +1,317 @@
+/*
+ * 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.camera.core.processing
+
+import android.graphics.Matrix
+import android.graphics.Rect
+import android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW
+import android.media.ImageReader
+import android.os.Handler
+import android.os.HandlerThread
+import android.util.Size
+import android.view.Surface
+import androidx.camera.core.SurfaceOutput
+import androidx.camera.core.SurfaceRequest
+import androidx.camera.core.impl.DeferrableSurface
+import androidx.camera.core.impl.ImageFormatConstants
+import androidx.camera.core.impl.ImmediateSurface
+import androidx.camera.core.impl.utils.executor.CameraXExecutors
+import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.HandlerUtil
+import androidx.camera.testing.fakes.FakeCamera
+import androidx.concurrent.futures.await
+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.ExecutionException
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.android.asCoroutineDispatcher
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.collectIndexed
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withTimeoutOrNull
+import org.junit.After
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+@SdkSuppress(minSdkVersion = 21)
+class DefaultSurfaceEffectTest {
+
+    companion object {
+        private const val WIDTH = 640
+        private const val HEIGHT = 480
+        private val IDENTITY_MATRIX = createGlIdentityMatrix()
+
+        private fun createGlIdentityMatrix() =
+            FloatArray(16).apply { android.opengl.Matrix.setIdentityM(this, 0) }
+
+        @JvmStatic
+        lateinit var testCameraRule: CameraUtil.PreTestCamera
+
+        @JvmStatic
+        lateinit var testCameraIdListRule: CameraUtil.PreTestCameraIdList
+
+        @BeforeClass
+        @JvmStatic
+        fun classSetup() {
+            // In order to test camera just once, keep the test rules.
+            testCameraRule = CameraUtil.PreTestCamera()
+            testCameraIdListRule = CameraUtil.PreTestCameraIdList()
+        }
+    }
+
+    @get:Rule
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(testCameraRule, testCameraIdListRule)
+
+    private lateinit var surfaceEffect: DefaultSurfaceEffect
+    private lateinit var cameraDeviceHolder: CameraUtil.CameraDeviceHolder
+    private lateinit var handlerThread: HandlerThread
+    private lateinit var handler: Handler
+    private lateinit var dispatcher: CoroutineDispatcher
+    private val inputSurfaceRequestsToClose = mutableListOf<SurfaceRequest>()
+    private val settableSurfacesToClose = mutableMapOf<SettableSurface, DeferrableSurface>()
+    private val fakeCamera = FakeCamera()
+
+    @Before
+    fun setUp() {
+        surfaceEffect = DefaultSurfaceEffect()
+    }
+
+    @After
+    fun tearDown(): Unit = runBlocking {
+        if (::cameraDeviceHolder.isInitialized) {
+            CameraUtil.releaseCameraDevice(cameraDeviceHolder)
+        }
+        if (::surfaceEffect.isInitialized) {
+            surfaceEffect.release()
+            surfaceEffect.awaitReleased(10_000L)
+        }
+        if (::handlerThread.isInitialized) {
+            handlerThread.quitSafely()
+        }
+        for (surfaceRequest in inputSurfaceRequestsToClose) {
+            surfaceRequest.deferrableSurface.close()
+        }
+        for ((settableSurface, sourceSurface) in settableSurfacesToClose) {
+            settableSurface.close()
+            sourceSurface.close()
+        }
+    }
+
+    @Test
+    fun release_closeAllSurfaceOutputs(): Unit = runBlocking {
+        // Arrange.
+        val surfaceOutput1 = createSurfaceOutput()
+        surfaceEffect.onOutputSurface(surfaceOutput1)
+
+        val surfaceOutput2 = createSurfaceOutput()
+        surfaceEffect.onOutputSurface(surfaceOutput2)
+
+        surfaceEffect.idle()
+
+        // Act.
+        surfaceEffect.release()
+        surfaceEffect.awaitReleased(5000)
+
+        // Assert.
+        assertThat(surfaceOutput1.isClosed).isTrue()
+        assertThat(surfaceOutput2.isClosed).isTrue()
+    }
+
+    @Test
+    fun callOnInputSurfaceAfterReleased_willNotProvideSurface() {
+        // Arrange.
+        val surfaceRequest = createInputSurfaceRequest()
+
+        // Act.
+        surfaceEffect.release()
+        surfaceEffect.onInputSurface(surfaceRequest)
+
+        // Assert.
+        try {
+            surfaceRequest.deferrableSurface.surface.get()
+        } catch (e: ExecutionException) {
+            assertThat(e.cause)
+                .isInstanceOf(DeferrableSurface.SurfaceUnavailableException::class.java)
+        }
+    }
+
+    @Test
+    fun callOnOutputSurfaceAfterReleased_closeSurfaceOutput(): Unit = runBlocking {
+        // Arrange.
+        val surfaceOutput = createSurfaceOutput()
+
+        // Act.
+        surfaceEffect.release()
+        surfaceEffect.awaitReleased()
+        surfaceEffect.onOutputSurface(surfaceOutput)
+
+        // Assert.
+        assertThat(surfaceOutput.isClosed).isTrue()
+    }
+
+    @Test
+    fun requestCloseAfterOnOutputSurface_closeSurfaceOutput() {
+        // Arrange.
+        val sourceSurface = ImmediateSurface(mock(Surface::class.java))
+        val settableSurface = createSettableSurface(sourceSurface)
+        val surfaceOutput = createSurfaceOutput(settableSurface)
+
+        // Act.
+        surfaceEffect.onOutputSurface(surfaceOutput)
+        surfaceEffect.idle()
+        surfaceOutput.requestClose()
+        surfaceEffect.idle()
+
+        // Assert.
+        assertThat(surfaceOutput.isClosed).isTrue()
+
+        // Clean-up.
+        settableSurface.close()
+        sourceSurface.close()
+    }
+
+    @Test
+    fun requestCloseBeforeOnOutputSurface_closeSurfaceOutput() {
+        // Arrange.
+        val surfaceOutput = createSurfaceOutput()
+
+        // Act.
+        surfaceOutput.requestClose()
+        surfaceEffect.onOutputSurface(surfaceOutput)
+        surfaceEffect.idle()
+
+        // Assert.
+        assertThat(surfaceOutput.isClosed).isTrue()
+    }
+
+    @Test
+    fun inputFromCameraAndOutputToImageReader(): Unit = runBlocking {
+        prepareHandlerThread()
+        // Prepare input
+        val inputSurfaceRequest = createInputSurfaceRequest()
+        surfaceEffect.onInputSurface(inputSurfaceRequest)
+        val inputDeferrableSurface = inputSurfaceRequest.deferrableSurface
+        val inputSurface = inputDeferrableSurface.surface.await()
+        openCameraAndSetRepeating(inputSurface)
+        cameraDeviceHolder.closedFuture.addListener({
+            inputDeferrableSurface.close()
+        }, CameraXExecutors.directExecutor())
+
+        // Prepare output
+        val imageReader = ImageReader.newInstance(
+            WIDTH,
+            HEIGHT,
+            ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
+            2
+        )
+        val scope = CoroutineScope(dispatcher)
+        val imageCollectJob = scope.launch {
+            callbackFlow {
+                val listener = ImageReader.OnImageAvailableListener {
+                    trySend(it.acquireLatestImage())
+                }
+                imageReader.setOnImageAvailableListener(listener, handler)
+                awaitClose { imageReader.close() }
+            }.collectIndexed { index, image ->
+                image.close()
+                if (index >= 4) {
+                    // stop the collect job
+                    scope.cancel()
+                }
+            }
+        }
+        val surfaceOutput = createSurfaceOutput(
+            settableSurface = createSettableSurface(ImmediateSurface(imageReader.surface))
+        )
+        surfaceEffect.onOutputSurface(surfaceOutput)
+
+        // Assert.
+        withTimeoutOrNull(10_000L) {
+            imageCollectJob.join()
+            true
+        } ?: fail("Timed out to receive images")
+    }
+
+    private fun prepareHandlerThread() {
+        handlerThread = HandlerThread("Worker").apply { start() }
+        handler = Handler(handlerThread.looper)
+        dispatcher = handler.asCoroutineDispatcher()
+    }
+
+    private fun openCameraAndSetRepeating(surface: Surface) {
+        cameraDeviceHolder = CameraUtil.getCameraDevice(null)
+        val captureSessionHolder = cameraDeviceHolder.createCaptureSession(listOf(surface))
+        captureSessionHolder.startRepeating(
+            TEMPLATE_PREVIEW,
+            listOf(surface),
+            null,
+            null)
+    }
+
+    private fun createInputSurfaceRequest(): SurfaceRequest {
+        return SurfaceRequest(Size(WIDTH, HEIGHT), fakeCamera, false).apply {
+            inputSurfaceRequestsToClose.add(this)
+        }
+    }
+
+    private fun createSurfaceOutput(settableSurface: SettableSurface = createSettableSurface()) =
+        SurfaceOutputImpl(settableSurface, IDENTITY_MATRIX)
+
+    private fun createSettableSurface(
+        source: DeferrableSurface = ImmediateSurface(mock(Surface::class.java))
+    ) = SettableSurface(
+        SurfaceOutput.PREVIEW,
+        Size(WIDTH, HEIGHT),
+        ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE,
+        Matrix(),
+        false,
+        Rect(0, 0, WIDTH, HEIGHT),
+        0,
+        false
+    ).apply {
+        settableSurfacesToClose[this] = source
+        setSource(source)
+    }
+
+    private fun DefaultSurfaceEffect.idle() {
+        HandlerUtil.waitForLooperToIdle(mGlHandler)
+    }
+
+    private suspend fun DefaultSurfaceEffect.awaitReleased(timeoutMs: Long = 5000L) {
+        withTimeoutOrNull(timeoutMs) {
+            while (true) {
+                delay(500L)
+                if (!mGlThread.isAlive) break
+            }
+            true
+        } ?: fail("Timed out $timeoutMs milli-second to wait released")
+    }
+}
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/OpenGlRendererTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/OpenGlRendererTest.kt
new file mode 100644
index 0000000..27e8e8d
--- /dev/null
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/processing/OpenGlRendererTest.kt
@@ -0,0 +1,263 @@
+/*
+ * 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.camera.core.processing
+
+import android.graphics.ImageFormat
+import android.graphics.SurfaceTexture
+import android.hardware.camera2.CameraDevice
+import android.media.Image
+import android.media.ImageReader
+import android.opengl.Matrix
+import android.os.Handler
+import android.os.HandlerThread
+import android.view.Surface
+import androidx.camera.core.impl.utils.executor.CameraXExecutors
+import androidx.camera.testing.CameraUtil
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.testutils.assertThrows
+import androidx.testutils.fail
+import com.google.common.truth.Truth.assertThat
+import kotlin.coroutines.ContinuationInterceptor
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.android.asCoroutineDispatcher
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.currentCoroutineContext
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.collectIndexed
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+import kotlinx.coroutines.withTimeoutOrNull
+import org.junit.After
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+@SdkSuppress(minSdkVersion = 21)
+class OpenGlRendererTest {
+
+    companion object {
+        private const val WIDTH = 640
+        private const val HEIGHT = 480
+        private val IDENTITY_MATRIX = createGlIdentityMatrix()
+
+        private fun createGlIdentityMatrix() = FloatArray(16).apply { Matrix.setIdentityM(this, 0) }
+
+        @JvmStatic
+        lateinit var testCameraRule: CameraUtil.PreTestCamera
+
+        @JvmStatic
+        lateinit var testCameraIdListRule: CameraUtil.PreTestCameraIdList
+
+        @BeforeClass
+        @JvmStatic
+        fun classSetup() {
+            // In order to test camera just once, keep the test rules.
+            testCameraRule = CameraUtil.PreTestCamera()
+            testCameraIdListRule = CameraUtil.PreTestCameraIdList()
+        }
+    }
+
+    @get:Rule
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(testCameraRule, testCameraIdListRule)
+
+    private lateinit var glThread: HandlerThread
+    private lateinit var glHandler: Handler
+    private lateinit var glDispatcher: CoroutineDispatcher
+    private lateinit var glRenderer: OpenGlRenderer
+    private lateinit var cameraDeviceHolder: CameraUtil.CameraDeviceHolder
+
+    @Before
+    fun setUp() {
+        glThread = HandlerThread("GL Thread").apply { start() }
+        glHandler = Handler(glThread.looper)
+        glDispatcher = glHandler.asCoroutineDispatcher()
+    }
+
+    @After
+    fun tearDown(): Unit = runBlocking {
+        if (::cameraDeviceHolder.isInitialized) {
+            CameraUtil.releaseCameraDevice(cameraDeviceHolder)
+        }
+        if (::glRenderer.isInitialized) {
+            withContext(glDispatcher) {
+                glRenderer.release()
+            }
+        }
+        if (::glThread.isInitialized) {
+            glThread.quitSafely()
+        }
+    }
+
+    @Test
+    fun getTextureNameWithoutInit_throwException(): Unit = runBlocking(glDispatcher) {
+        createOpenGlRenderer()
+        assertThrows(IllegalStateException::class.java) {
+            glRenderer.textureName
+        }
+    }
+
+    @Test
+    fun setOutputSurfaceWithoutInit_throwException(): Unit = runBlocking(glDispatcher) {
+        createOpenGlRenderer()
+        assertThrows(IllegalStateException::class.java) {
+            glRenderer.setOutputSurface(mock(Surface::class.java))
+        }
+    }
+
+    @Test
+    fun renderWithoutInit_throwException(): Unit = runBlocking(glDispatcher) {
+        createOpenGlRenderer()
+        assertThrows(IllegalStateException::class.java) {
+            glRenderer.render(123L, IDENTITY_MATRIX)
+        }
+    }
+
+    @Test
+    fun releaseWithoutInit_noOp(): Unit = runBlocking(glDispatcher) {
+        createOpenGlRenderer()
+        glRenderer.release()
+    }
+
+    @Test
+    fun getTextureNameOnNonGlThread_throwException(): Unit = runBlocking {
+        createOpenGlRendererAndInit()
+        assertThrows(IllegalStateException::class.java) {
+            glRenderer.textureName
+        }
+    }
+
+    @Test
+    fun setOutputSurfaceOnNonGlThread_throwException(): Unit = runBlocking {
+        createOpenGlRendererAndInit()
+        assertThrows(IllegalStateException::class.java) {
+            glRenderer.setOutputSurface(mock(Surface::class.java))
+        }
+    }
+
+    @Test
+    fun renderOnNonGlThread_throwException(): Unit = runBlocking {
+        createOpenGlRendererAndInit()
+        assertThrows(IllegalStateException::class.java) {
+            glRenderer.render(123L, IDENTITY_MATRIX)
+        }
+    }
+
+    @Test
+    fun releaseOnNonGlThread_throwException(): Unit = runBlocking {
+        createOpenGlRendererAndInit()
+        assertThrows(IllegalStateException::class.java) {
+            glRenderer.release()
+        }
+    }
+
+    @Test
+    fun reInit(): Unit = runBlocking(glDispatcher) {
+        createOpenGlRendererAndInit()
+        glRenderer.release()
+        glRenderer.init()
+        assertThat(glRenderer.textureName).isNotEqualTo(0L)
+    }
+
+    @Test
+    fun renderFromCameraToImageReader(): Unit = runBlocking(glDispatcher) {
+        // Arrange.
+        createOpenGlRendererAndInit()
+
+        // Prepare input
+        val surfaceTexture = SurfaceTexture(glRenderer.textureName).apply {
+            setDefaultBufferSize(WIDTH, HEIGHT)
+        }
+        val inputSurface = Surface(surfaceTexture)
+        openCameraAndSetRepeating(inputSurface)
+        cameraDeviceHolder.closedFuture.addListener({
+            inputSurface.release()
+            surfaceTexture.release()
+        }, CameraXExecutors.directExecutor())
+
+        // Prepare output
+        val imageReader =
+            ImageReader.newInstance(WIDTH, HEIGHT, ImageFormat.PRIVATE, 2)
+        val imageFlow = callbackFlow<Image> {
+            val listener = ImageReader.OnImageAvailableListener {
+                trySend(it.acquireLatestImage())
+            }
+            imageReader.setOnImageAvailableListener(listener, glHandler)
+            awaitClose { imageReader.close() }
+        }
+
+        // Bridge input to output
+        surfaceTexture.setOnFrameAvailableListener({
+            it.updateTexImage()
+            glRenderer.setOutputSurface(imageReader.surface)
+            glRenderer.render(0L, IDENTITY_MATRIX)
+        }, glHandler)
+
+        val scope = CoroutineScope(glDispatcher)
+        val imageCollectJob = scope.launch {
+            imageFlow.collectIndexed { index, image ->
+                image.close()
+                if (index >= 4) {
+                    scope.cancel()
+                }
+            }
+        }
+
+        // Assert.
+        withTimeoutOrNull(10_000L) {
+            imageCollectJob.join()
+            true
+        } ?: fail("Timed out to receive images")
+    }
+
+    private suspend fun createOpenGlRendererAndInit() {
+        createOpenGlRenderer()
+
+        if (currentCoroutineContext()[ContinuationInterceptor] == glDispatcher) {
+            // same dispatcher, init directly
+            glRenderer.init()
+        } else {
+            runBlocking(glDispatcher) {
+                glRenderer.init()
+            }
+        }
+    }
+
+    private fun createOpenGlRenderer() {
+        glRenderer = OpenGlRenderer()
+    }
+
+    private fun openCameraAndSetRepeating(surface: Surface) {
+        cameraDeviceHolder = CameraUtil.getCameraDevice(null)
+        val captureSessionHolder = cameraDeviceHolder.createCaptureSession(listOf(surface))
+        captureSessionHolder.startRepeating(
+            CameraDevice.TEMPLATE_PREVIEW,
+            listOf(surface),
+            null,
+            null
+        )
+    }
+}
diff --git a/camera/camera-core/src/main/cpp/CMakeLists.txt b/camera/camera-core/src/main/cpp/CMakeLists.txt
index 82acb5c..f3576ee 100644
--- a/camera/camera-core/src/main/cpp/CMakeLists.txt
+++ b/camera/camera-core/src/main/cpp/CMakeLists.txt
@@ -27,3 +27,18 @@
 find_package(libyuv REQUIRED)
 
 target_link_libraries(image_processing_util_jni PRIVATE ${log-lib} ${android-lib} libyuv::yuv)
+
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror")
+
+add_library(
+        camerax_core_opengl_renderer_jni SHARED
+        jni_hooks.cpp
+        opengl_renderer_jni.cpp)
+
+find_library(log-lib log)
+find_library(android-lib android)
+find_library(opengl-lib GLESv2)
+find_library(egl-lib EGL)
+
+target_link_libraries(camerax_core_opengl_renderer_jni ${log-lib} ${android-lib} ${opengl-lib} ${egl-lib})
diff --git a/camera/camera-core/src/main/cpp/jni_hooks.cpp b/camera/camera-core/src/main/cpp/jni_hooks.cpp
new file mode 100644
index 0000000..f5d05db
--- /dev/null
+++ b/camera/camera-core/src/main/cpp/jni_hooks.cpp
@@ -0,0 +1,7 @@
+#include <jni.h>
+
+extern "C" {
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
+    return JNI_VERSION_1_6;
+}
+}
\ No newline at end of file
diff --git a/camera/camera-core/src/main/cpp/opengl_renderer_jni.cpp b/camera/camera-core/src/main/cpp/opengl_renderer_jni.cpp
new file mode 100644
index 0000000..1a44b59
--- /dev/null
+++ b/camera/camera-core/src/main/cpp/opengl_renderer_jni.cpp
@@ -0,0 +1,558 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#include <android/log.h>
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <EGL/eglplatform.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <jni.h>
+
+#include <cassert>
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace {
+    auto constexpr LOG_TAG = "GLRendererJni";
+
+    std::string GLErrorString(GLenum error) {
+        switch (error) {
+            case GL_NO_ERROR:
+                return "GL_NO_ERROR";
+            case GL_INVALID_ENUM:
+                return "GL_INVALID_ENUM";
+            case GL_INVALID_VALUE:
+                return "GL_INVALID_VALUE";
+            case GL_INVALID_OPERATION:
+                return "GL_INVALID_OPERATION";
+            case GL_STACK_OVERFLOW_KHR:
+                return "GL_STACK_OVERFLOW";
+            case GL_STACK_UNDERFLOW_KHR:
+                return "GL_STACK_UNDERFLOW";
+            case GL_OUT_OF_MEMORY:
+                return "GL_OUT_OF_MEMORY";
+            case GL_INVALID_FRAMEBUFFER_OPERATION:
+                return "GL_INVALID_FRAMEBUFFER_OPERATION";
+            default: {
+                std::ostringstream oss;
+                oss << "<Unknown GL Error 0x" << std::setfill('0') <<
+                    std::setw(4) << std::right << std::hex << error << ">";
+                return oss.str();
+            }
+        }
+    }
+
+    std::string EGLErrorString(EGLenum error) {
+        switch (error) {
+            case EGL_SUCCESS:
+                return "EGL_SUCCESS";
+            case EGL_NOT_INITIALIZED:
+                return "EGL_NOT_INITIALIZED";
+            case EGL_BAD_ACCESS:
+                return "EGL_BAD_ACCESS";
+            case EGL_BAD_ALLOC:
+                return "EGL_BAD_ALLOC";
+            case EGL_BAD_ATTRIBUTE:
+                return "EGL_BAD_ATTRIBUTE";
+            case EGL_BAD_CONTEXT:
+                return "EGL_BAD_CONTEXT";
+            case EGL_BAD_CONFIG:
+                return "EGL_BAD_CONFIG";
+            case EGL_BAD_CURRENT_SURFACE:
+                return "EGL_BAD_CURRENT_SURFACE";
+            case EGL_BAD_DISPLAY:
+                return "EGL_BAD_DISPLAY";
+            case EGL_BAD_SURFACE:
+                return "EGL_BAD_SURFACE";
+            case EGL_BAD_MATCH:
+                return "EGL_BAD_MATCH";
+            case EGL_BAD_PARAMETER:
+                return "EGL_BAD_PARAMETER";
+            case EGL_BAD_NATIVE_PIXMAP:
+                return "EGL_BAD_NATIVE_PIXMAP";
+            case EGL_BAD_NATIVE_WINDOW:
+                return "EGL_BAD_NATIVE_WINDOW";
+            case EGL_CONTEXT_LOST:
+                return "EGL_CONTEXT_LOST";
+            default: {
+                std::ostringstream oss;
+                oss << "<Unknown EGL Error 0x" << std::setfill('0') <<
+                    std::setw(4) << std::right << std::hex << error << ">";
+                return oss.str();
+            }
+        }
+    }
+}
+
+#ifdef NDEBUG
+#define CHECK_GL(gl_func) [&]() { return gl_func; }()
+#else
+namespace {
+    class CheckGlErrorOnExit {
+    public:
+        explicit CheckGlErrorOnExit(std::string glFunStr, unsigned int lineNum) :
+                mGlFunStr(std::move(glFunStr)),
+                mLineNum(lineNum) {}
+
+        ~CheckGlErrorOnExit() {
+            GLenum err = glGetError();
+            if (err != GL_NO_ERROR) {
+                __android_log_assert(nullptr, LOG_TAG, "OpenGL Error: %s at %s [%s:%d]",
+                                     GLErrorString(err).c_str(), mGlFunStr.c_str(), __FILE__,
+                                     mLineNum);
+            }
+        }
+
+        CheckGlErrorOnExit(const CheckGlErrorOnExit &) = delete;
+
+        CheckGlErrorOnExit &operator=(const CheckGlErrorOnExit &) = delete;
+
+    private:
+        std::string mGlFunStr;
+        unsigned int mLineNum;
+    };  // class CheckGlErrorOnExit
+}   // namespace
+#define CHECK_GL(glFunc)                                                    \
+  [&]() {                                                                   \
+    auto assertOnExit = CheckGlErrorOnExit(#glFunc, __LINE__);              \
+    return glFunc;                                                          \
+  }()
+#endif
+
+namespace {
+    constexpr char VERTEX_SHADER_SRC[] = R"SRC(
+      attribute vec4 position;
+      attribute vec4 texCoords;
+      uniform mat4 texTransform;
+      varying vec2 fragCoord;
+      void main() {
+        fragCoord = (texTransform * texCoords).xy;
+        gl_Position = position;
+      }
+)SRC";
+
+    constexpr char FRAGMENT_SHADER_SRC[] = R"SRC(
+      #extension GL_OES_EGL_image_external : require
+      precision mediump float;
+      uniform samplerExternalOES sampler;
+      varying vec2 fragCoord;
+      void main() {
+        gl_FragColor = texture2D(sampler, fragCoord);
+      }
+)SRC";
+
+    // We use two triangles drawn with GL_TRIANGLE_STRIP to create the surface which will be
+    // textured with the camera frame. This could also be done with a quad (GL_QUADS) on a
+    // different version of OpenGL or with a scaled single triangle in which we would inscribe
+    // the camera texture.
+    //
+    //                       (-1,1)           (1,1)
+    //                          +---------------+
+    //                          | \_            |
+    //                          |    \_         |
+    //                          |       +       |
+    //                          |         \_    |
+    //                          |            \_ |
+    //                          +---------------+
+    //                       (-1,-1)          (1,-1)
+    constexpr GLfloat VERTICES[] = {
+            -1.0f, -1.0f, // Lower-left
+            1.0f, -1.0f, // Lower-right
+            -1.0f,  1.0f, // Upper-left (notice order here. We're drawing triangles, not a quad.)
+            1.0f,  1.0f  // Upper-right
+    };
+    constexpr GLfloat TEX_COORDS[] = {
+            0.0f, 0.0f, // Lower-left
+            1.0f, 0.0f, // Lower-right
+            0.0f, 1.0f, // Upper-left (order must match the VERTICES)
+            1.0f, 1.0f  // Upper-right
+    };
+
+    struct NativeContext {
+        EGLDisplay display;
+        EGLConfig config;
+        EGLContext context;
+        std::pair<ANativeWindow *, EGLSurface> windowSurface;
+        EGLSurface pbufferSurface;
+        GLuint program;
+        GLint positionHandle;
+        GLint texCoordsHandle;
+        GLint samplerHandle;
+        GLint texTransformHandle;
+        GLuint textureId;
+
+        NativeContext(EGLDisplay display, EGLConfig config, EGLContext context,
+                      ANativeWindow *window, EGLSurface surface,
+                      EGLSurface pbufferSurface)
+                : display(display),
+                  config(config),
+                  context(context),
+                  windowSurface(std::make_pair(window, surface)),
+                  pbufferSurface(pbufferSurface),
+                  program(0),
+                  positionHandle(-1),
+                  texCoordsHandle(1),
+                  samplerHandle(-1),
+                  texTransformHandle(-1),
+                  textureId(0) {}
+    };
+
+    const char *ShaderTypeString(GLenum shaderType) {
+        switch (shaderType) {
+            case GL_VERTEX_SHADER:
+                return "GL_VERTEX_SHADER";
+            case GL_FRAGMENT_SHADER:
+                return "GL_FRAGMENT_SHADER";
+            default:
+                return "<Unknown shader type>";
+        }
+    }
+
+    // Returns a handle to the shader
+    GLuint CompileShader(GLenum shaderType, const char *shaderSrc) {
+        GLuint shader = CHECK_GL(glCreateShader(shaderType));
+        assert(shader);
+        CHECK_GL(glShaderSource(shader, 1, &shaderSrc, /*length=*/nullptr));
+        CHECK_GL(glCompileShader(shader));
+        GLint compileStatus = 0;
+        CHECK_GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus));
+        if (!compileStatus) {
+            GLint logLength = 0;
+            CHECK_GL(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength));
+            std::vector<char> logBuffer(logLength);
+            if (logLength > 0) {
+                CHECK_GL(glGetShaderInfoLog(shader, logLength, /*length=*/nullptr,
+                                            &logBuffer[0]));
+            }
+            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+                                "Unable to compile %s shader:\n %s.",
+                                ShaderTypeString(shaderType),
+                                logLength > 0 ? &logBuffer[0] : "(unknown error)");
+            CHECK_GL(glDeleteShader(shader));
+            shader = 0;
+        }
+        assert(shader);
+        return shader;
+    }
+
+    // Returns a handle to the output program
+    GLuint CreateGlProgram() {
+        GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, VERTEX_SHADER_SRC);
+        assert(vertexShader);
+
+        GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER_SRC);
+        assert(fragmentShader);
+
+        GLuint program = CHECK_GL(glCreateProgram());
+        assert(program);
+        CHECK_GL(glAttachShader(program, vertexShader));
+        CHECK_GL(glAttachShader(program, fragmentShader));
+        CHECK_GL(glLinkProgram(program));
+        GLint linkStatus = 0;
+        CHECK_GL(glGetProgramiv(program, GL_LINK_STATUS, &linkStatus));
+        if (!linkStatus) {
+            GLint logLength = 0;
+            CHECK_GL(glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength));
+            std::vector<char> logBuffer(logLength);
+            if (logLength > 0) {
+                CHECK_GL(glGetProgramInfoLog(program, logLength, /*length=*/nullptr,
+                                             &logBuffer[0]));
+            }
+            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+                                "Unable to link program:\n %s.",
+                                logLength > 0 ? &logBuffer[0] : "(unknown error)");
+            CHECK_GL(glDeleteProgram(program));
+            program = 0;
+        }
+        assert(program);
+        return program;
+    }
+
+    void DestroySurface(NativeContext *nativeContext) {
+        if (nativeContext->windowSurface.first) {
+            eglMakeCurrent(nativeContext->display, nativeContext->pbufferSurface,
+                           nativeContext->pbufferSurface, nativeContext->context);
+            eglDestroySurface(nativeContext->display,
+                              nativeContext->windowSurface.second);
+            nativeContext->windowSurface.second = nullptr;
+            ANativeWindow_release(nativeContext->windowSurface.first);
+            nativeContext->windowSurface.first = nullptr;
+        }
+    }
+
+    void ThrowException(JNIEnv *env, const char *exceptionName, const char *msg) {
+        jclass exClass = env->FindClass(exceptionName);
+        assert(exClass != nullptr);
+
+        [[maybe_unused]] jint throwSuccess = env->ThrowNew(exClass, msg);
+        assert(throwSuccess == JNI_OK);
+    }
+
+}  // namespace
+
+extern "C" {
+JNIEXPORT jlong JNICALL
+Java_androidx_camera_core_processing_OpenGlRenderer_initContext(
+        JNIEnv *env, jclass clazz) {
+    EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    assert(eglDisplay != EGL_NO_DISPLAY);
+
+    EGLint majorVer;
+    EGLint minorVer;
+    EGLBoolean initSuccess = eglInitialize(eglDisplay, &majorVer, &minorVer);
+    if (initSuccess != EGL_TRUE) {
+        ThrowException(env, "java/lang/RuntimeException",
+                       "EGL Error: eglInitialize failed.");
+        return 0;
+    }
+
+    // Print debug EGL information
+    const char *eglVendorString = eglQueryString(eglDisplay, EGL_VENDOR);
+    const char *eglVersionString = eglQueryString(eglDisplay, EGL_VERSION);
+    __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "EGL Initialized [Vendor: %s, Version: %s]",
+                        eglVendorString == nullptr ? "Unknown" : eglVendorString,
+                        eglVersionString == nullptr
+                        ? "Unknown" : eglVersionString);
+
+    int configAttribs[] = {EGL_RENDERABLE_TYPE,
+                           EGL_OPENGL_ES2_BIT,
+                           EGL_SURFACE_TYPE,
+                           EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
+                           EGL_RECORDABLE_ANDROID,
+                           EGL_TRUE,
+                           EGL_NONE};
+    EGLConfig config;
+    EGLint numConfigs;
+    EGLint configSize = 1;
+    EGLBoolean chooseConfigSuccess =
+            eglChooseConfig(eglDisplay, static_cast<EGLint *>(configAttribs), &config,
+                            configSize, &numConfigs);
+    if (chooseConfigSuccess != EGL_TRUE) {
+        ThrowException(env, "java/lang/IllegalArgumentException",
+                       "EGL Error: eglChooseConfig failed. ");
+        return 0;
+    }
+    assert(numConfigs > 0);
+
+    int contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+    EGLContext eglContext = eglCreateContext(
+            eglDisplay, config, EGL_NO_CONTEXT, static_cast<EGLint *>(contextAttribs));
+    assert(eglContext != EGL_NO_CONTEXT);
+
+    // Create 1x1 pixmap to use as a surface until one is set.
+    int pbufferAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
+    EGLSurface eglPbuffer =
+            eglCreatePbufferSurface(eglDisplay, config, pbufferAttribs);
+    assert(eglPbuffer != EGL_NO_SURFACE);
+
+    eglMakeCurrent(eglDisplay, eglPbuffer, eglPbuffer, eglContext);
+
+    //Print debug OpenGL information
+    const GLubyte *glVendorString = CHECK_GL(glGetString(GL_VENDOR));
+    const GLubyte *glVersionString = CHECK_GL(glGetString(GL_VERSION));
+    const GLubyte *glslVersionString = CHECK_GL(glGetString(GL_SHADING_LANGUAGE_VERSION));
+    const GLubyte *glRendererString = CHECK_GL(glGetString(GL_RENDERER));
+    __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "OpenGL Initialized [Vendor: %s, Version: %s,"
+                                                    " GLSL Version: %s, Renderer: %s]",
+                        glVendorString == nullptr ? "Unknown" : (const char *) glVendorString,
+                        glVersionString == nullptr ? "Unknown" : (const char *) glVersionString,
+                        glslVersionString == nullptr ? "Unknown" : (const char *) glslVersionString,
+                        glRendererString == nullptr ? "Unknown" : (const char *) glRendererString);
+
+    auto *nativeContext =
+            new NativeContext(eglDisplay, config, eglContext, /*window=*/nullptr,
+                    /*surface=*/nullptr, eglPbuffer);
+
+    nativeContext->program = CreateGlProgram();
+    assert(nativeContext->program);
+
+    nativeContext->positionHandle =
+            CHECK_GL(glGetAttribLocation(nativeContext->program, "position"));
+    assert(nativeContext->positionHandle != -1);
+
+    nativeContext->texCoordsHandle =
+            CHECK_GL(glGetAttribLocation(nativeContext->program, "texCoords"));
+    assert(nativeContext->texCoordsHandle != -1);
+
+    nativeContext->samplerHandle =
+            CHECK_GL(glGetUniformLocation(nativeContext->program, "sampler"));
+    assert(nativeContext->samplerHandle != -1);
+
+    nativeContext->texTransformHandle =
+            CHECK_GL(glGetUniformLocation(nativeContext->program, "texTransform"));
+    assert(nativeContext->texTransformHandle != -1);
+
+    CHECK_GL(glGenTextures(1, &(nativeContext->textureId)));
+
+    return reinterpret_cast<jlong>(nativeContext);
+}
+
+JNIEXPORT jboolean JNICALL
+Java_androidx_camera_core_processing_OpenGlRenderer_setWindowSurface(
+        JNIEnv *env, jclass clazz, jlong context, jobject jsurface) {
+    auto *nativeContext = reinterpret_cast<NativeContext *>(context);
+
+    // Destroy previously connected surface
+    DestroySurface(nativeContext);
+
+    // Null surface may have just been passed in to destroy previous surface.
+    if (!jsurface) {
+        return JNI_FALSE;
+    }
+
+    ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, jsurface);
+    if (nativeWindow == nullptr) {
+        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Failed to set window surface: Unable to "
+                                                        "acquire native window.");
+        return JNI_FALSE;
+    }
+
+    EGLSurface surface =
+            eglCreateWindowSurface(nativeContext->display, nativeContext->config,
+                                   nativeWindow, /*attrib_list=*/nullptr);
+    assert(surface != EGL_NO_SURFACE);
+
+    nativeContext->windowSurface = std::make_pair(nativeWindow, surface);
+
+    eglMakeCurrent(nativeContext->display, surface, surface,
+                   nativeContext->context);
+
+    CHECK_GL(glViewport(0, 0, ANativeWindow_getWidth(nativeWindow),
+                        ANativeWindow_getHeight(nativeWindow)));
+    CHECK_GL(glScissor(0, 0, ANativeWindow_getWidth(nativeWindow),
+                       ANativeWindow_getHeight(nativeWindow)));
+
+    return JNI_TRUE;
+}
+
+JNIEXPORT jint JNICALL
+Java_androidx_camera_core_processing_OpenGlRenderer_getTexName(
+        JNIEnv *env, jclass clazz, jlong context) {
+    auto *nativeContext = reinterpret_cast<NativeContext *>(context);
+    return nativeContext->textureId;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_androidx_camera_core_processing_OpenGlRenderer_renderTexture(
+        JNIEnv *env, jclass clazz, jlong context, jlong timestampNs,
+        jfloatArray jtexTransformArray) {
+    auto *nativeContext = reinterpret_cast<NativeContext *>(context);
+
+    GLint vertexComponents = 2;
+    GLenum vertexType = GL_FLOAT;
+    GLboolean normalized = GL_FALSE;
+    GLsizei vertexStride = 0;
+    CHECK_GL(glVertexAttribPointer(nativeContext->positionHandle,
+                                   vertexComponents, vertexType, normalized,
+                                   vertexStride, VERTICES));
+    CHECK_GL(glEnableVertexAttribArray(nativeContext->positionHandle));
+
+    CHECK_GL(glVertexAttribPointer(nativeContext->texCoordsHandle,
+                                   vertexComponents, vertexType, normalized,
+                                   vertexStride, TEX_COORDS));
+    CHECK_GL(glEnableVertexAttribArray(nativeContext->texCoordsHandle));
+
+    CHECK_GL(glUseProgram(nativeContext->program));
+
+    GLsizei numMatrices = 1;
+    GLboolean transpose = GL_FALSE;
+
+    CHECK_GL(glUniform1i(nativeContext->samplerHandle, 0));
+
+    numMatrices = 1;
+    transpose = GL_FALSE;
+    GLfloat *texTransformArray =
+            env->GetFloatArrayElements(jtexTransformArray, nullptr);
+    CHECK_GL(glUniformMatrix4fv(nativeContext->texTransformHandle, numMatrices,
+                                transpose, texTransformArray));
+    env->ReleaseFloatArrayElements(jtexTransformArray, texTransformArray,
+                                   JNI_ABORT);
+
+    CHECK_GL(glBindTexture(GL_TEXTURE_EXTERNAL_OES, nativeContext->textureId));
+
+    // This will typically fail if the EGL surface has been detached abnormally. In that case we
+    // will return JNI_FALSE below.
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+    // Check that all GL operations completed successfully. If not, log an error and return.
+    GLenum glError = glGetError();
+    if (glError != GL_NO_ERROR) {
+        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+                            "Failed to draw frame due to OpenGL error: %s",
+                            GLErrorString(glError).c_str());
+        return JNI_FALSE;
+    }
+
+    // Disable vertex array, texture, and program.
+    CHECK_GL(glDisableVertexAttribArray(nativeContext->positionHandle));
+
+    CHECK_GL(glDisableVertexAttribArray(nativeContext->texCoordsHandle));
+
+    CHECK_GL(glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0));
+
+    CHECK_GL(glUseProgram(0));
+
+// Only attempt to set presentation time if EGL_EGLEXT_PROTOTYPES is defined.
+// Otherwise, we'll ignore the timestamp.
+#ifdef EGL_EGLEXT_PROTOTYPES
+    eglPresentationTimeANDROID(nativeContext->display,
+                               nativeContext->windowSurface.second, timestampNs);
+#endif  // EGL_EGLEXT_PROTOTYPES
+    EGLBoolean swapped = eglSwapBuffers(nativeContext->display,
+                                        nativeContext->windowSurface.second);
+    if (!swapped) {
+        EGLenum eglError = eglGetError();
+        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+                            "Failed to swap buffers with EGL error: %s",
+                            EGLErrorString(eglError).c_str());
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+JNIEXPORT void JNICALL
+Java_androidx_camera_core_processing_OpenGlRenderer_closeContext(
+        JNIEnv *env, jclass clazz, jlong context) {
+    auto *nativeContext = reinterpret_cast<NativeContext *>(context);
+
+    if (nativeContext->program) {
+        CHECK_GL(glDeleteProgram(nativeContext->program));
+        nativeContext->program = 0;
+    }
+
+    DestroySurface(nativeContext);
+
+    eglDestroySurface(nativeContext->display, nativeContext->pbufferSurface);
+
+    eglMakeCurrent(nativeContext->display, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                   EGL_NO_CONTEXT);
+
+    eglDestroyContext(nativeContext->display, nativeContext->context);
+
+    eglTerminate(nativeContext->display);
+
+    delete nativeContext;
+}
+}  // extern "C"
+
+#undef CHECK_GL
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/AndroidImageProxy.java b/camera/camera-core/src/main/java/androidx/camera/core/AndroidImageProxy.java
index 2cba273..b321d30 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/AndroidImageProxy.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/AndroidImageProxy.java
@@ -20,7 +20,6 @@
 import android.graphics.Rect;
 import android.media.Image;
 
-import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
@@ -31,10 +30,8 @@
 /** An {@link ImageProxy} which wraps around an {@link Image}. */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 final class AndroidImageProxy implements ImageProxy {
-    @GuardedBy("this")
     private final Image mImage;
 
-    @GuardedBy("this")
     private final PlaneProxy[] mPlanes;
 
     private final ImageInfo mImageInfo;
@@ -66,45 +63,44 @@
     }
 
     @Override
-    public synchronized void close() {
+    public void close() {
         mImage.close();
     }
 
     @Override
     @NonNull
-    public synchronized Rect getCropRect() {
+    public Rect getCropRect() {
         return mImage.getCropRect();
     }
 
     @Override
-    public synchronized void setCropRect(@Nullable Rect rect) {
+    public void setCropRect(@Nullable Rect rect) {
         mImage.setCropRect(rect);
     }
 
     @Override
-    public synchronized int getFormat() {
+    public int getFormat() {
         return mImage.getFormat();
     }
 
     @Override
-    public synchronized int getHeight() {
+    public int getHeight() {
         return mImage.getHeight();
     }
 
     @Override
-    public synchronized int getWidth() {
+    public int getWidth() {
         return mImage.getWidth();
     }
 
     @Override
     @NonNull
-    public synchronized ImageProxy.PlaneProxy[] getPlanes() {
+    public ImageProxy.PlaneProxy[] getPlanes() {
         return mPlanes;
     }
 
     /** An {@link ImageProxy.PlaneProxy} which wraps around an {@link Image.Plane}. */
     private static final class PlaneProxy implements ImageProxy.PlaneProxy {
-        @GuardedBy("this")
         private final Image.Plane mPlane;
 
         PlaneProxy(Image.Plane plane) {
@@ -112,18 +108,18 @@
         }
 
         @Override
-        public synchronized int getRowStride() {
+        public int getRowStride() {
             return mPlane.getRowStride();
         }
 
         @Override
-        public synchronized int getPixelStride() {
+        public int getPixelStride() {
             return mPlane.getPixelStride();
         }
 
         @Override
         @NonNull
-        public synchronized ByteBuffer getBuffer() {
+        public ByteBuffer getBuffer() {
             return mPlane.getBuffer();
         }
     }
@@ -136,7 +132,7 @@
 
     @Override
     @ExperimentalGetImage
-    public synchronized Image getImage() {
+    public Image getImage() {
         return mImage;
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ForwardingImageProxy.java b/camera/camera-core/src/main/java/androidx/camera/core/ForwardingImageProxy.java
index 672dd35..03a638e 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ForwardingImageProxy.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ForwardingImageProxy.java
@@ -38,17 +38,17 @@
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 abstract class ForwardingImageProxy implements ImageProxy {
-    @GuardedBy("this")
+    private final Object mLock = new Object();
+
     protected final ImageProxy mImage;
 
-    @GuardedBy("this")
+    @GuardedBy("mLock")
     private final Set<OnImageCloseListener> mOnImageCloseListeners = new HashSet<>();
 
     /**
      * Creates a new instance which wraps the given image.
      *
      * @param image to wrap
-     * @return new {@link AndroidImageProxy} instance
      */
     protected ForwardingImageProxy(ImageProxy image) {
         mImage = image;
@@ -56,53 +56,51 @@
 
     @Override
     public void close() {
-        synchronized (this) {
-            mImage.close();
-        }
+        mImage.close();
         notifyOnImageCloseListeners();
     }
 
     @Override
     @NonNull
-    public synchronized Rect getCropRect() {
+    public Rect getCropRect() {
         return mImage.getCropRect();
     }
 
     @Override
-    public synchronized void setCropRect(@Nullable Rect rect) {
+    public void setCropRect(@Nullable Rect rect) {
         mImage.setCropRect(rect);
     }
 
     @Override
-    public synchronized int getFormat() {
+    public int getFormat() {
         return mImage.getFormat();
     }
 
     @Override
-    public synchronized int getHeight() {
+    public int getHeight() {
         return mImage.getHeight();
     }
 
     @Override
-    public synchronized int getWidth() {
+    public int getWidth() {
         return mImage.getWidth();
     }
 
     @Override
     @NonNull
-    public synchronized ImageProxy.PlaneProxy[] getPlanes() {
+    public ImageProxy.PlaneProxy[] getPlanes() {
         return mImage.getPlanes();
     }
 
     @Override
     @NonNull
-    public synchronized ImageInfo getImageInfo() {
+    public ImageInfo getImageInfo() {
         return mImage.getImageInfo();
     }
 
     @Override
     @ExperimentalGetImage
-    public synchronized Image getImage() {
+    public Image getImage() {
         return mImage.getImage();
     }
 
@@ -111,14 +109,16 @@
      *
      * @param listener to add
      */
-    synchronized void addOnImageCloseListener(OnImageCloseListener listener) {
-        mOnImageCloseListeners.add(listener);
+    void addOnImageCloseListener(OnImageCloseListener listener) {
+        synchronized (mLock) {
+            mOnImageCloseListeners.add(listener);
+        }
     }
 
     /** Notifies the listeners that this image has been closed. */
     protected void notifyOnImageCloseListeners() {
         Set<OnImageCloseListener> onImageCloseListeners;
-        synchronized (this) {
+        synchronized (mLock) {
             // Make a copy for thread safety. We want to synchronize the access for member variables
             // but not the actual callbacks to avoid a deadlock between ForwardingImageProxy and
             // QueuedImageReaderProxy. go/deadlock-in-sharedimagereaderproxy
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
index b2ac134..27c5d88 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
@@ -163,6 +163,10 @@
      * <p>All {@link ImageProxy} sent to {@link Analyzer#analyze(ImageProxy)} will have
      * format {@link android.graphics.PixelFormat#RGBA_8888}
      *
+     * <p>The output order is a single-plane with the order of R, G, B, A in increasing byte index
+     * in the {@link java.nio.ByteBuffer}. The {@link java.nio.ByteBuffer} is retrieved from
+     * {@link ImageProxy.PlaneProxy#getBuffer()}.
+     *
      * @see Builder#setOutputImageFormat(int)
      */
     public static final int OUTPUT_IMAGE_FORMAT_RGBA_8888 = 2;
@@ -256,9 +260,11 @@
         Size analyzerResolution;
         synchronized (mAnalysisLock) {
             analyzerResolution = mSubscribedAnalyzer != null
-                    ? mSubscribedAnalyzer.getTargetResolutionOverride() : null;
+                    ? mSubscribedAnalyzer.getDefaultTargetResolution() : null;
         }
-        if (analyzerResolution != null) {
+
+        if (analyzerResolution != null
+                && !builder.getUseCaseConfig().containsOption(OPTION_TARGET_RESOLUTION)) {
             builder.getMutableConfig().insertOption(OPTION_TARGET_RESOLUTION, analyzerResolution);
         }
 
@@ -794,22 +800,27 @@
         void analyze(@NonNull ImageProxy image);
 
         /**
-         * Implement this method to override the target resolution of {@link ImageAnalysis}.
+         * Implement this method to set a default target resolution for the {@link ImageAnalysis}.
          *
          * <p> Implement this method if the {@link Analyzer} requires a specific resolution to
-         * work. The return value will be used to override the target resolution of the
-         * {@link ImageAnalysis}. Return {@code null} if no overriding is needed. By default,
+         * work. The return value will be used as the default target resolution for the
+         * {@link ImageAnalysis}. Return {@code null} if no falling back is needed. By default,
          * this method returns {@code null}.
          *
+         * <p> If the app does not set a target resolution for {@link ImageAnalysis}, then this
+         * value will be used as the target resolution. If the {@link ImageAnalysis} has set a
+         * target resolution, e.g. if {@link ImageAnalysis.Builder#setTargetResolution(Size)} is
+         * called, then the {@link ImageAnalysis} will use the app value over this value.
+         *
          * <p> Note that this method is invoked by CameraX at the time of binding to lifecycle. In
          * order for this value to be effective, the {@link Analyzer} has to be set before
          * {@link ImageAnalysis} is bound to a lifecycle. Otherwise, the value will be ignored.
          *
-         * @return the resolution to override the target resolution of {@link ImageAnalysis}, or
-         * {@code null} if no overriding is needed.
+         * @return the default resolution of {@link ImageAnalysis}, or {@code null} if no specific
+         * resolution is needed.
          */
         @Nullable
-        default Size getTargetResolutionOverride() {
+        default Size getDefaultTargetResolution() {
             return null;
         }
 
@@ -842,10 +853,16 @@
          * by the implementation to transform the coordinates detected in the camera frame. For
          * example, the coordinates of the detected face.
          *
-         * <p>If the value is {@code null}, it could either mean value of the target coordinate
-         * system is {@link #COORDINATE_SYSTEM_ORIGINAL}, or currently there is no valid
-         * transformation for the target coordinate system, for example, if currently the view
-         * finder is not visible in UI.
+         * <p>If the value is {@code null}, it means that no valid transformation is available.
+         * It could have different causes depending on the value of
+         * {@link #getTargetCoordinateSystem()}:
+         * <ul>
+         *     <li> If the target coordinate system is {@link #COORDINATE_SYSTEM_ORIGINAL}, it is
+         *     always invalid because in that case, the coordinate system depends on how the
+         *     analysis algorithm processes the {@link ImageProxy}.
+         *     <li> It is also invalid if the target coordinate system is not available, for example
+         *     if the analyzer targets the viewfinder and the view finder is not visible in UI.
+         * </ul>
          *
          * <p>This method is invoked whenever a new transformation is ready. For example, when
          * the view finder is first a launched as well as when it's resized.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index 5b6abb7..ce77f21 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -124,6 +124,7 @@
 import java.nio.ByteBuffer;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Deque;
 import java.util.List;
 import java.util.Locale;
@@ -540,6 +541,11 @@
         sessionConfigBuilder.addNonRepeatingSurface(mDeferrableSurface);
 
         sessionConfigBuilder.addErrorListener((sessionConfig, error) -> {
+            // Get the unfinished requests before re-create the pipeline
+            List<ImageCaptureRequest> pendingRequests = (mImageCaptureRequestProcessor != null)
+                    ? mImageCaptureRequestProcessor.pullOutUnfinishedRequests()
+                    : Collections.emptyList();
+
             clearPipeline();
             // Ensure the attached camera has not changed before resetting.
             // TODO(b/143915543): Ensure this never gets called by a camera that is not attached
@@ -547,6 +553,14 @@
             if (isCurrentCamera(cameraId)) {
                 // Only reset the pipeline when the bound camera is the same.
                 mSessionConfigBuilder = createPipeline(cameraId, config, resolution);
+
+                if (mImageCaptureRequestProcessor != null) {
+                    // Restore the unfinished requests to the created pipeline
+                    for (ImageCaptureRequest request: pendingRequests) {
+                        mImageCaptureRequestProcessor.sendRequest(request);
+                    }
+                }
+
                 updateSessionConfig(mSessionConfigBuilder.build());
                 notifyReset();
             }
@@ -563,6 +577,7 @@
         CameraConfig cameraConfig = getCamera().getExtendedConfig();
         return cameraConfig == null ? false : cameraConfig.getSessionProcessor(null) != null;
     }
+
     /**
      * Clear the internal pipeline so that the pipeline can be set up again.
      */
@@ -1420,6 +1435,36 @@
             }
         }
 
+        /**
+         * Removes and returns all unfinished requests.
+         *
+         * <p>The unfinished requests include:
+         * <ul>
+         *     <li>Current running request if it is not complete yet.</li>
+         *     <li>All pending requests.</li>
+         * </ul>
+         *
+         * @return list of the remaining requests
+         */
+        @NonNull
+        public List<ImageCaptureRequest> pullOutUnfinishedRequests() {
+            List<ImageCaptureRequest> remainingRequests;
+            synchronized (mLock) {
+                remainingRequests = new ArrayList<>(mPendingRequests);
+                // Clear the pending requests before canceling the mCurrentRequestFuture.
+                mPendingRequests.clear();
+
+                ImageCaptureRequest currentRequest = mCurrentRequest;
+                mCurrentRequest = null;
+                if (currentRequest != null && mCurrentRequestFuture != null
+                        && mCurrentRequestFuture.cancel(true)) {
+                    remainingRequests.add(0, currentRequest);
+                }
+            }
+
+            return remainingRequests;
+        }
+
         @Override
         public void onImageClose(ImageProxy image) {
             synchronized (mLock) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageProxyDownsampler.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageProxyDownsampler.java
index b7a2eb9..7bf8d92 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageProxyDownsampler.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageProxyDownsampler.java
@@ -237,18 +237,18 @@
         }
 
         @Override
-        public synchronized int getWidth() {
+        public int getWidth() {
             return mDownsampledWidth;
         }
 
         @Override
-        public synchronized int getHeight() {
+        public int getHeight() {
             return mDownsampledHeight;
         }
 
         @Override
         @NonNull
-        public synchronized PlaneProxy[] getPlanes() {
+        public PlaneProxy[] getPlanes() {
             return mDownsampledPlanes;
         }
     }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/SettableImageProxy.java b/camera/camera-core/src/main/java/androidx/camera/core/SettableImageProxy.java
index 3c45ed6..99e7789 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/SettableImageProxy.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/SettableImageProxy.java
@@ -19,6 +19,7 @@
 import android.graphics.Rect;
 import android.util.Size;
 
+import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
@@ -27,9 +28,11 @@
  * An {@link ImageProxy} which overwrites the {@link ImageInfo}.
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-final class SettableImageProxy extends ForwardingImageProxy{
+final class SettableImageProxy extends ForwardingImageProxy {
+    private final Object mLock = new Object();
     private final ImageInfo mImageInfo;
 
+    @GuardedBy("mLock")
     @Nullable
     private Rect mCropRect;
 
@@ -67,36 +70,39 @@
 
     @NonNull
     @Override
-    public synchronized Rect getCropRect() {
-        if (mCropRect == null) {
-            return new Rect(0, 0, getWidth(), getHeight());
-        } else {
-            return new Rect(mCropRect); // return a copy
+    public Rect getCropRect() {
+        synchronized (mLock) {
+            if (mCropRect == null) {
+                return new Rect(0, 0, getWidth(), getHeight());
+            } else {
+                return new Rect(mCropRect); // return a copy
+            }
         }
     }
 
     @Override
-    public synchronized void setCropRect(@Nullable Rect cropRect) {
+    public void setCropRect(@Nullable Rect cropRect) {
         if (cropRect != null) {
             cropRect = new Rect(cropRect);  // make a copy
             if (!cropRect.intersect(0, 0, getWidth(), getHeight())) {
                 cropRect.setEmpty();
             }
         }
-        mCropRect = cropRect;
+        synchronized (mLock) {
+            mCropRect = cropRect;
+        }
     }
 
     @Override
-    public synchronized int getWidth() {
+    public int getWidth() {
         return mWidth;
     }
 
     @Override
-    public synchronized int getHeight() {
+    public int getHeight() {
         return mHeight;
     }
 
-    @SuppressWarnings("UnsynchronizedOverridesSynchronized")
     @Override
     @NonNull
     public ImageInfo getImageInfo() {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/SingleCloseImageProxy.java b/camera/camera-core/src/main/java/androidx/camera/core/SingleCloseImageProxy.java
index a6ddb1e..241e803 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/SingleCloseImageProxy.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/SingleCloseImageProxy.java
@@ -16,14 +16,14 @@
 
 package androidx.camera.core;
 
-import androidx.annotation.GuardedBy;
 import androidx.annotation.RequiresApi;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 /** A {@link ImageProxy} which filters out redundant calls to {@link #close()}. */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 final class SingleCloseImageProxy extends ForwardingImageProxy {
-    @GuardedBy("this")
-    private boolean mClosed = false;
+    private final AtomicBoolean mClosed = new AtomicBoolean(false);
 
     /**
      * Creates a new instances which wraps the given image.
@@ -36,9 +36,8 @@
     }
 
     @Override
-    public synchronized void close() {
-        if (!mClosed) {
-            mClosed = true;
+    public void close() {
+        if (!mClosed.getAndSet(true)) {
             super.close();
         }
     }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceEffect.java b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceEffect.java
new file mode 100644
index 0000000..e0588f0
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceEffect.java
@@ -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.camera.core;
+
+import android.graphics.SurfaceTexture;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+
+/**
+ * Interface for injecting a {@link Surface}-based post-processing effect into CameraX.
+ *
+ * <p> TODO(b/233280438): update JavaDoc before going for API review.
+ *
+ * <p>Currently, this is only used by internal implementations such as "video cropping" and
+ * "video recording during front/back camera switch". The interfaces themselves are also
+ * placeholders and subject to change depending on API/design review. Moving forward, these
+ * interfaces will be made public to developers and move to "androidx.camera.core".
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public interface SurfaceEffect {
+
+    /**
+     * Invoked when the upstream pipeline requires a {@link Surface} to write to.
+     *
+     * <p> The implementation is expected t o create a {@link Surface} backed
+     * by{@link SurfaceTexture}, then listen for the
+     * {@link SurfaceTexture#setOnFrameAvailableListener} to get the incoming upstream frames.
+     *
+     * @param request a request to provide {@link Surface} for input.
+     */
+    void onInputSurface(@NonNull SurfaceRequest request);
+
+    /**
+     * Invoked when the downstream pipeline provide Surface(s) to be written to.
+     *
+     * <p> The implementation is expected to draw processed frames to the {@link Surface}
+     * acquired via {@link SurfaceOutput#getSurface} following specification defined in the said
+     * {@link SurfaceOutput}.
+     *
+     * @param surfaceOutput a list of {@link SurfaceOutput}. For non stream sharing cases, the list
+     *                      will only contain one element.
+     */
+    void onOutputSurface(@NonNull SurfaceOutput surfaceOutput);
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceOutput.java b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceOutput.java
new file mode 100644
index 0000000..639ef55
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceOutput.java
@@ -0,0 +1,137 @@
+/*
+ * 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.camera.core;
+
+import android.graphics.SurfaceTexture;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A completable, single-use {@link Surface} for outputting processed camera frames.
+ *
+ * <p>Contains a {@link ListenableFuture<Surface>} and its characteristics along with methods
+ * for notifying the end of life of the {@link Surface} and marking the {@link Surface} as no
+ * longer in use.
+ *
+ * @hide
+ * @see SurfaceEffect#onOutputSurface(SurfaceOutput)
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public interface SurfaceOutput {
+
+    /**
+     * Bitmask option to indicate that this Surface will be used by CameraX as the output of the
+     * {@link Preview} {@link UseCase}.
+     */
+    int PREVIEW = 1;
+
+    /**
+     * Bitmask option to indicate that this Surface will be used by CameraX as the output of
+     * video capture {@link UseCase}.
+     */
+    int VIDEO = 1 << 1;
+
+    /**
+     * Gets the output {@link Surface} for writing processed frames.
+     *
+     * <p> If there are multiple calls to the method, only the {@link OnCloseRequestedListener}
+     * from the last call will be triggerd.
+     *
+     * @param executor on which the listener should be invoked.
+     * @param listener a listener to notify the implementation about the end-of-life of the
+     *                 {@link SurfaceOutput}. The implementation should then invoke
+     *                 {@link #close()} to mark the {@link Surface} as no longer in use.
+     * @see OnCloseRequestedListener
+     */
+    @NonNull
+    Surface getSurface(
+            @NonNull Executor executor,
+            @NonNull OnCloseRequestedListener listener);
+
+    /**
+     * This field indicates that what purpose the {@link Surface} will be used for.
+     *
+     * - {@link #PREVIEW} if the {@link Surface} will be used for {@link Preview}.
+     * - {@link #VIDEO} if the {@link Surface} will be used for video capture.
+     * - {@code PREVIEW|VIDEO} if the output {@link Surface} will be used for sharing a
+     * single stream for both preview and video capture.
+     */
+    int getTargets();
+
+    /**
+     * Gets the size of the {@link Surface}.
+     */
+    @NonNull
+    Size getSize();
+
+    /**
+     * Gets the format of the {@link Surface}.
+     */
+    int getFormat();
+
+    /**
+     * Call this method to mark the {@link Surface} provided via {@link #getSurface} as no longer in
+     * use.
+     *
+     * <p>After this is called, the implementation should stop writing to the {@link Surface}.
+     */
+    void close();
+
+    /**
+     * Updates the 4 x 4 transformation matrix retrieved from {@link SurfaceTexture
+     * #getTransformMatrix}.
+     *
+     * <p>This method applies an additional transformation on top of the value of
+     * {@link SurfaceTexture#getTransformMatrix}. The result is matrix of the same format, which
+     * is a transform matrix maps 2D homogeneous texture coordinates of the form (s, t, 0, 1)
+     * with s and t in the inclusive range [0, 1] to the texture coordinate that should be used
+     * to sample that location from the texture. The result should be used in the same way as
+     * the original matrix. Please see the Javadoc of {@link SurfaceTexture#getTransformMatrix}.
+     *
+     * <p>The additional transformation is calculated based on the target rotation, target
+     * resolution and the {@link ViewPort} configured by the app. The value could also include
+     * workaround for device specific quirks.
+     *
+     * @param updated  the array into which the 4x4 matrix will be stored. The array must
+     *                 have exactly 16 elements.
+     * @param original the original value retrieved from
+     *                 {@link SurfaceTexture#getTransformMatrix}. The array must have exactly 16
+     *                 elements.
+     * @see SurfaceTexture#getTransformMatrix(float[])
+     */
+    void updateTransformMatrix(@NonNull float[] updated, @NonNull float[] original);
+
+    /**
+     * A listener to notify the implementation about the end-of-life of the {@link Surface}.
+     */
+    interface OnCloseRequestedListener {
+
+        /**
+         * After this is invoked, the implementation should finish the current access to the
+         * {@link Surface}, stop writing to the {@link Surface} and mark the
+         * {@link SurfaceOutput} as closed by calling {@link SurfaceOutput#close()}.
+         */
+        void onCloseRequested();
+    }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/SessionConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/SessionConfig.java
index 73747cf..1620e3d 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/SessionConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/SessionConfig.java
@@ -47,6 +47,9 @@
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public final class SessionConfig {
+    /** The value represents an unset or unsupported stream use case. */
+    private static final long STREAM_USE_CASE_NONE = -1;
+
     /** The set of {@link OutputConfig} that data from the camera will be put into. */
     private final List<OutputConfig> mOutputConfigs;
     /** The state callback for a {@link CameraDevice}. */
@@ -58,6 +61,8 @@
     private final List<ErrorListener> mErrorListeners;
     /** The configuration for building the {@link CaptureRequest} used for repeating requests. */
     private final CaptureConfig mRepeatingCaptureConfig;
+    /** The stream use case for the capture session. */
+    private final long mStreamUseCase;
 
     /**
      * Immutable class to store an input configuration that is used to create a reprocessable
@@ -173,6 +178,7 @@
      * @param repeatingCaptureConfig The configuration for building the {@link CaptureRequest}.
      * @param inputConfiguration     The input configuration to create a reprocessable capture
      *                               session.
+     * @param streamUseCase          The value of stream use case for the capture session.
      */
     SessionConfig(
             List<OutputConfig> outputConfigs,
@@ -181,7 +187,8 @@
             List<CameraCaptureCallback> singleCameraCaptureCallbacks,
             List<ErrorListener> errorListeners,
             CaptureConfig repeatingCaptureConfig,
-            @Nullable InputConfiguration inputConfiguration) {
+            @Nullable InputConfiguration inputConfiguration,
+            long streamUseCase) {
         mOutputConfigs = outputConfigs;
         mDeviceStateCallbacks = Collections.unmodifiableList(deviceStateCallbacks);
         mSessionStateCallbacks = Collections.unmodifiableList(sessionStateCallbacks);
@@ -190,6 +197,7 @@
         mErrorListeners = Collections.unmodifiableList(errorListeners);
         mRepeatingCaptureConfig = repeatingCaptureConfig;
         mInputConfiguration = inputConfiguration;
+        mStreamUseCase = streamUseCase;
     }
 
     /** Returns an instance of a session configuration with minimal configurations. */
@@ -202,7 +210,8 @@
                 new ArrayList<CameraCaptureCallback>(0),
                 new ArrayList<>(0),
                 new CaptureConfig.Builder().build(),
-                /* inputConfiguration */ null);
+                /* inputConfiguration */ null,
+                /* streamUseCase */ STREAM_USE_CASE_NONE);
     }
 
     @Nullable
@@ -241,6 +250,10 @@
         return mRepeatingCaptureConfig.getTemplateType();
     }
 
+    public long getStreamUseCase() {
+        return mStreamUseCase;
+    }
+
     /** Obtains all registered {@link CameraDevice.StateCallback} callbacks. */
     @NonNull
     public List<CameraDevice.StateCallback> getDeviceStateCallbacks() {
@@ -614,7 +627,8 @@
                     mSingleCameraCaptureCallbacks,
                     mErrorListeners,
                     mCaptureConfigBuilder.build(),
-                    mInputConfiguration);
+                    mInputConfiguration,
+                    /* streamUseCase */ STREAM_USE_CASE_NONE);
         }
     }
 
@@ -637,6 +651,11 @@
         private final SurfaceSorter mSurfaceSorter = new SurfaceSorter();
         private boolean mValid = true;
         private boolean mTemplateSet = false;
+        private long mStreamUseCase = STREAM_USE_CASE_NONE;
+
+        public void setStreamUseCase(long streamUseCase) {
+            mStreamUseCase = streamUseCase;
+        }
 
         /**
          * Add the SessionConfig to the set of SessionConfig that have been aggregated by the
@@ -738,7 +757,8 @@
                     mSingleCameraCaptureCallbacks,
                     mErrorListeners,
                     mCaptureConfigBuilder.build(),
-                    mInputConfiguration);
+                    mInputConfiguration,
+                    mStreamUseCase);
         }
 
         private int selectTemplateType(int type1, int type2) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/DefaultSurfaceEffect.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/DefaultSurfaceEffect.java
new file mode 100644
index 0000000..bfa19da
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/DefaultSurfaceEffect.java
@@ -0,0 +1,159 @@
+/*
+ * 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.camera.core.processing;
+
+import android.graphics.SurfaceTexture;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
+import androidx.camera.core.SurfaceEffect;
+import androidx.camera.core.SurfaceOutput;
+import androidx.camera.core.SurfaceRequest;
+import androidx.camera.core.impl.utils.executor.CameraXExecutors;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * A default implementation of {@link SurfaceEffect}.
+ *
+ * <p> This implementation simply copies the frame from the source to the destination with the
+ * transformation defined in {@link SurfaceOutput#updateTransformMatrix}.
+ */
+@RequiresApi(21)
+public class DefaultSurfaceEffect implements SurfaceEffect,
+        SurfaceTexture.OnFrameAvailableListener {
+    private final OpenGlRenderer mGlRenderer;
+    @VisibleForTesting
+    final HandlerThread mGlThread;
+    private final Executor mGlExecutor;
+    @VisibleForTesting
+    final Handler mGlHandler;
+    private final AtomicBoolean mIsReleased = new AtomicBoolean(false);
+    private final float[] mTextureMatrix = new float[16];
+    private final float[] mSurfaceOutputMatrix = new float[16];
+    // Map of current set of available outputs. Only access this on GL thread.
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    final Map<SurfaceOutput, Surface> mOutputSurfaces = new LinkedHashMap<>();
+
+    // Only access this on GL thread.
+    private int mInputSurfaceCount = 0;
+
+    public DefaultSurfaceEffect() {
+        mGlThread = new HandlerThread("GL Thread");
+        mGlThread.start();
+        mGlHandler = new Handler(mGlThread.getLooper());
+        mGlExecutor = CameraXExecutors.newHandlerExecutor(mGlHandler);
+        mGlRenderer = new OpenGlRenderer();
+        mGlExecutor.execute(mGlRenderer::init);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onInputSurface(@NonNull SurfaceRequest surfaceRequest) {
+        if (mIsReleased.get()) {
+            surfaceRequest.willNotProvideSurface();
+            return;
+        }
+        mGlExecutor.execute(() -> {
+            mInputSurfaceCount++;
+            SurfaceTexture surfaceTexture = new SurfaceTexture(mGlRenderer.getTextureName());
+            surfaceTexture.setDefaultBufferSize(surfaceRequest.getResolution().getWidth(),
+                    surfaceRequest.getResolution().getHeight());
+            Surface surface = new Surface(surfaceTexture);
+            surfaceRequest.provideSurface(surface, mGlExecutor, result -> {
+                surfaceTexture.setOnFrameAvailableListener(null);
+                surfaceTexture.release();
+                surface.release();
+                mInputSurfaceCount--;
+                checkReadyToRelease();
+            });
+            surfaceTexture.setOnFrameAvailableListener(this, mGlHandler);
+        });
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onOutputSurface(@NonNull SurfaceOutput surfaceOutput) {
+        if (mIsReleased.get()) {
+            surfaceOutput.close();
+            return;
+        }
+        mGlExecutor.execute(() ->
+                mOutputSurfaces.put(surfaceOutput, surfaceOutput.getSurface(mGlExecutor, () -> {
+                    surfaceOutput.close();
+                    mOutputSurfaces.remove(surfaceOutput);
+                }))
+        );
+    }
+
+    /**
+     * Release the DefaultSurfaceEffect
+     */
+    public void release() {
+        if (mIsReleased.getAndSet(true)) {
+            return;
+        }
+        mGlExecutor.execute(this::checkReadyToRelease);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onFrameAvailable(@NonNull SurfaceTexture surfaceTexture) {
+        if (mIsReleased.get()) {
+            // Ignore frame update if released.
+            return;
+        }
+
+        surfaceTexture.updateTexImage();
+        surfaceTexture.getTransformMatrix(mTextureMatrix);
+
+        for (Map.Entry<SurfaceOutput, Surface> entry : mOutputSurfaces.entrySet()) {
+            Surface surface = entry.getValue();
+            SurfaceOutput surfaceOutput = entry.getKey();
+            mGlRenderer.setOutputSurface(surface);
+            surfaceOutput.updateTransformMatrix(mSurfaceOutputMatrix, mTextureMatrix);
+            mGlRenderer.render(surfaceTexture.getTimestamp(), mSurfaceOutputMatrix);
+        }
+    }
+
+    @WorkerThread
+    private void checkReadyToRelease() {
+        if (mIsReleased.get() && mInputSurfaceCount == 0) {
+            // Once release is called, we can stop sending frame to output surfaces.
+            for (SurfaceOutput surfaceOutput : mOutputSurfaces.keySet()) {
+                surfaceOutput.close();
+            }
+            mOutputSurfaces.clear();
+            mGlRenderer.release();
+            mGlThread.quit();
+        }
+    }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/Node.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/Node.java
new file mode 100644
index 0000000..e3fefda
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/Node.java
@@ -0,0 +1,76 @@
+/*
+ * 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.camera.core.processing;
+
+import android.view.Surface;
+
+import androidx.annotation.MainThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.core.impl.CameraCaptureResult;
+
+/**
+ * Base unit for CameraX post-processing.
+ *
+ * <p>All CameraX post-processing should be wrapped by this interface to explicitly define the I/O.
+ *
+ * <p>Both {@link InputSpec} and {@link OutputSpec} should include handlers to buffers that
+ * contain camera frames, as well as the callbacks to notify when the frames are updated. One
+ * example of such buffer is a {@link Surface}. e.g. {@link Surface} itself is a handler to a
+ * {@code GraphicBuffer}, and one can get the callback in the form of {@code SurfaceTexture
+ * .OnFrameAvailableListener} or{@link android.media.ImageReader.OnImageAvailableListener}.
+ *
+ * <p>The buffers are usually for image frames, but they could also contain other types of data
+ * such as {@link CameraCaptureResult}, EXIF or depth. Both input and output could contain one
+ * or multiple buffers. If there are multiple inputs and/or outputs, it's the implementation's
+ * responsibility to properly share or merge the streams.
+ *
+ * <p>Besides the buffers, the I/O usually carry additional information about the buffer, such
+ * as dimension, format and transformation. Usually, the {@link InputSpec} includes instructions on
+ * how the buffer should be edited. If there are multiple outputs, there should be one
+ * instruction per output streams.
+ *
+ * <p>The pipeline will be built in the direction from the camera to the app. The input of the
+ * first node will be the direct output from the camera. Each subsequent node provide buffers for
+ * the upstream nodes to write to, and demand buffers from the downstream nodes. For the nodes
+ * that doing actual image processing, they usually need to allocate and maintain buffers.
+ *
+ * <p>Nodes should be stateful, e.g. keeping track of the previous I/O and the buffer allocated,
+ * so that the pipeline can be partially recreated for efficiency. For example, one may need to
+ * change post-processing effects without reconfiguring the {@link Surface}s for camera output and
+ * app display.
+ *
+ * @param <InputSpec>  input specifications
+ * @param <OutputSpec> output specifications
+ */
+public interface Node<InputSpec, OutputSpec> {
+
+    /**
+     * Transforms an input specification to an output specification.
+     *
+     * <p>This method will be invoked in {@code UseCase#createPipeline}. For now, {@code
+     * #createPipeline}s are called on the main thread.
+     *
+     * <p> Returns {@code null} if the input does not change the current state of the
+     * {@link Node}. This usually happens when the input specification can be handled by the
+     * previously allocated buffer, thus no new buffer needs to be allocated. The node will
+     * provide the existing buffer for the upstream node to write to.
+     */
+    @Nullable
+    @MainThread
+    OutputSpec transform(@NonNull InputSpec inputSpec);
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/OpenGlRenderer.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/OpenGlRenderer.java
new file mode 100644
index 0000000..abb849f
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/OpenGlRenderer.java
@@ -0,0 +1,142 @@
+/*
+ * 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.camera.core.processing;
+
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.WorkerThread;
+import androidx.core.util.Preconditions;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * OpenGLRenderer renders texture image to the output surface.
+ *
+ * <p>OpenGLRenderer's methods must run on the same thread, so called GL thread. The GL thread is
+ * locked as the thread running the {@link #init()} method, otherwise an
+ * {@link IllegalStateException} will be thrown when other methods are called.
+ */
+@WorkerThread
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+public final class OpenGlRenderer {
+    static {
+        System.loadLibrary("camerax_core_opengl_renderer_jni");
+    }
+
+    private final AtomicBoolean mInitialized = new AtomicBoolean(false);
+    private final ThreadLocal<Long> mNativeContext = new ThreadLocal<>();
+
+    /**
+     * Initializes the OpenGLRenderer
+     *
+     * <p>Initialization must be done before calling other methods, otherwise an
+     * {@link IllegalStateException} will be thrown. Following methods must run on the same
+     * thread as this method, so called GL thread, otherwise an {@link IllegalStateException}
+     * will be thrown.
+     *
+     * @throws IllegalStateException if the renderer is already initialized.
+     */
+    public void init() {
+        checkInitializedOrThrow(false);
+        mNativeContext.set(initContext());
+        mInitialized.set(true);
+    }
+
+    /**
+     * Releases the OpenGLRenderer
+     *
+     * @throws IllegalStateException if the caller doesn't run on the GL thread.
+     */
+    public void release() {
+        if (!mInitialized.getAndSet(false)) {
+            return;
+        }
+        long nativeContext = getNativeContextOrThrow();
+        closeContext(nativeContext);
+        mNativeContext.remove();
+    }
+
+    /**
+     * Set the output surface.
+     *
+     * @throws IllegalStateException if the renderer is not initialized or the caller doesn't run
+     * on the GL thread.
+     */
+    public void setOutputSurface(@NonNull Surface surface) {
+        checkInitializedOrThrow(true);
+        long nativeContext = getNativeContextOrThrow();
+
+        setWindowSurface(nativeContext, surface);
+    }
+
+    /**
+     * Gets the texture name.
+     *
+     * @return the texture name
+     * @throws IllegalStateException if the renderer is not initialized or the caller doesn't run
+     * on the GL thread.
+     */
+    public int getTextureName() {
+        checkInitializedOrThrow(true);
+        long nativeContext = getNativeContextOrThrow();
+
+        return getTexName(nativeContext);
+    }
+
+    /**
+     * Renders the texture image to the output surface.
+     *
+     * @throws IllegalStateException if the renderer is not initialized or the caller doesn't run
+     * on the GL thread.
+     */
+    public void render(long timestampNs, @NonNull float[] textureTransform) {
+        checkInitializedOrThrow(true);
+        long nativeContext = getNativeContextOrThrow();
+
+        renderTexture(nativeContext, timestampNs, textureTransform);
+    }
+
+    private void checkInitializedOrThrow(boolean shouldInitialized) {
+        boolean result = shouldInitialized == mInitialized.get();
+        String message = shouldInitialized ? "OpenGlRenderer is not initialized"
+                : "OpenGlRenderer is already initialized";
+        Preconditions.checkState(result, message);
+    }
+
+    private long getNativeContextOrThrow() {
+        Long nativeContext = mNativeContext.get();
+        Preconditions.checkState(nativeContext != null,
+                "Method call must be called on the GL thread.");
+        return nativeContext;
+    }
+
+    private static native long initContext();
+
+    private static native boolean setWindowSurface(long nativeContext, @Nullable Surface surface);
+
+    private static native int getTexName(long nativeContext);
+
+    private static native boolean renderTexture(
+            long nativeContext,
+            long timestampNs,
+            @NonNull float[] textureTransform);
+
+    private static native void closeContext(long nativeContext);
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SettableSurface.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SettableSurface.java
new file mode 100644
index 0000000..ffde0f7
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SettableSurface.java
@@ -0,0 +1,237 @@
+/*
+ * 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.camera.core.processing;
+
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.Size;
+import android.view.Surface;
+import android.view.SurfaceView;
+import android.view.TextureView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.camera.core.SurfaceRequest;
+import androidx.camera.core.UseCase;
+import androidx.camera.core.impl.CameraInternal;
+import androidx.camera.core.impl.DeferrableSurface;
+import androidx.camera.core.impl.utils.futures.Futures;
+import androidx.concurrent.futures.CallbackToFutureAdapter;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * A {@link DeferrableSurface} with another {@link DeferrableSurface} as its source.
+ */
+@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+public class SettableSurface extends DeferrableSurface {
+
+    private final ListenableFuture<Surface> mSurfaceFuture;
+
+    CallbackToFutureAdapter.Completer<Surface> mCompleter;
+
+    private final Matrix mSensorToBufferTransform;
+    private final boolean mHasEmbeddedTransform;
+    private final Rect mCropRect;
+    private final int mRotationDegrees;
+    private final boolean mMirroring;
+    private final int mTargets;
+
+    private final AtomicBoolean mHasSource;
+
+    /**
+     * Please see the getters to understand the parameters.
+     */
+    public SettableSurface(
+            int targets,
+            @NonNull Size size,
+            int format,
+            @NonNull Matrix sensorToBufferTransform,
+            boolean hasEmbeddedTransform,
+            @NonNull Rect cropRect,
+            int rotationDegrees,
+            boolean mirroring) {
+        super(size, format);
+        mTargets = targets;
+        mSensorToBufferTransform = sensorToBufferTransform;
+        mHasEmbeddedTransform = hasEmbeddedTransform;
+        mCropRect = cropRect;
+        mRotationDegrees = rotationDegrees;
+        mMirroring = mirroring;
+        mHasSource = new AtomicBoolean(false);
+        mSurfaceFuture = CallbackToFutureAdapter.getFuture(
+                completer -> {
+                    mCompleter = completer;
+                    return null;
+                });
+    }
+
+    @NonNull
+    @Override
+    protected ListenableFuture<Surface> provideSurface() {
+        return mSurfaceFuture;
+    }
+
+    /**
+     * Sets the internal source of this {@link SettableSurface}.
+     *
+     * <p>This method is used to set a {@link DeferrableSurface} as the source of this
+     * {@link SettableSurface}. This is for organizing the pipeline internally. For example, using
+     * the output of one {@link UseCase} as the input of another {@link UseCase} for stream sharing.
+     *
+     * <p>It's also useful to link a new buffer request to an existing buffer, when the pipeline
+     * is rebuilt partially. Example:
+     *
+     * <pre><code>
+     * class NodeImplementation implements Node<SurfaceIn, SurfaceOut> {
+     *   SurfaceOut apply(SurfaceIn surfaceIn) {
+     *       if (canInputBeHandledByTheCurrentBuffer(surfaceIn)) {
+     *           surfaceIn.getSurface().setSource(currentBuffer.getDeferrableSurface());
+     *           // TODO(b/234174360): need to "unset" the existing link.
+     *           return null;
+     *       }
+     *   }
+     * }
+     * </code></pre>
+     *
+     * <p> It throws {@link IllegalStateException} if the current {@link SettableSurface}
+     * already has a source.
+     */
+    public void setSource(@NonNull DeferrableSurface source) {
+        // TODO(b/234174360): propagate the #close() call to the source. Usually if the current
+        //  DeferrableSurface is closed, the downstream one has to be closed as well. However, we
+        //  should be able to "unset" the Surface too. e.g. when the pipeline is partially rebuilt
+        //  during front/back camera switch VideoCapture, we don't want to propagate the close()
+        //  call to the recording Surface.
+        if (mHasSource.compareAndSet(false, true)) {
+            Futures.propagate(source.getSurface(), mCompleter);
+        } else {
+            throw new IllegalStateException("The source has already been set.");
+        }
+    }
+
+    /**
+     * Creates a {@link SurfaceRequest} as the external source of this {@link SettableSurface}.
+     *
+     * <p>This method is used to request a {@link Surface} from an external source such as
+     * {@code PreviewView}. The {@link Surface} provided via
+     * {@link SurfaceRequest#provideSurface} will be used as the source of this
+     * {@link SettableSurface}.
+     *
+     * <pre><code>
+     * SurfaceOut surfaceOut = finalNode.apply(surfaceIn);
+     * SurfaceRequest surfaceRequest = surfaceOut.getSurfaces().get(0)
+     *     .createSurfaceRequestAsSource(camera, false);
+     * mSurfaceProviderExecutor.execute(
+     *     () -> surfaceProvider.onSurfaceRequested(surfaceRequest));
+     * </code></pre>
+     *
+     * <p>It throws {@link IllegalStateException} if the current {@link SettableSurface}
+     * already has a source.
+     */
+    @NonNull
+    public SurfaceRequest createSurfaceRequestAsSource(@NonNull CameraInternal cameraInternal,
+            boolean isRGBA8888Required) {
+        SurfaceRequest surfaceRequest = new SurfaceRequest(getSize(), cameraInternal,
+                isRGBA8888Required);
+        setSource(surfaceRequest.getDeferrableSurface());
+        return surfaceRequest;
+    }
+
+    /**
+     * This field indicates that what purpose the {@link Surface} will be used for.
+     */
+    public int getTargets() {
+        return mTargets;
+    }
+
+    /**
+     * The allocated size of the {@link Surface}.
+     */
+    @NonNull
+    public Size getSize() {
+        return getPrescribedSize();
+    }
+
+    /**
+     * The format of the {@link Surface}.
+     */
+    public int getFormat() {
+        return getPrescribedStreamFormat();
+    }
+
+    /**
+     * Gets the {@link Matrix} represents the transformation from camera sensor to the current
+     * {@link Surface}.
+     *
+     * <p>This value represents the transformation from sensor coordinates to the current buffer
+     * coordinates, which is required to transform coordinates between UseCases. For example, in
+     * AR, transforming the coordinates of the detected face in ImageAnalysis to coordinates in
+     * PreviewView.
+     *
+     * <p> If the {@link SettableSurface} is directly connected to a camera output and its
+     * aspect ratio matches the aspect ratio of the sensor, this value is usually an identity
+     * matrix, with the exception of device quirks. Each time a intermediate {@link Node}
+     * transforms the image buffer, it has to append the same transformation to this
+     * {@link Matrix} and pass it to the downstream {@link Node}.
+     */
+    @NonNull
+    public Matrix getSensorToBufferTransform() {
+        return mSensorToBufferTransform;
+    }
+
+    /**
+     * Whether the current {@link Surface} has transformation info embedded.
+     *
+     * <p> Camera embeds transformation info into the {@link Surface}. The info is typically used by
+     * {@link SurfaceView}/{@link TextureView} to correct the preview transformation. After the
+     * buffer copy, the info is lost. The app (e.g. PreviewView) needs to handle the
+     * transformation differently based on this flag.
+     */
+    public boolean hasEmbeddedTransform() {
+        return mHasEmbeddedTransform;
+    }
+
+    // The following values represent the scenario that if this buffer is given directly to the
+    // app, these are the additional transformation needs to be applied by the app. Every time we
+    // make a change to the buffer, these values need to be updated as well.
+
+    /**
+     * Gets the crop rect based on {@link UseCase} config.
+     */
+    @NonNull
+    public Rect getCropRect() {
+        return mCropRect;
+    }
+
+    /**
+     * Gets the clockwise rotation degrees based on {@link UseCase} config.
+     */
+    public int getRotationDegrees() {
+        return mRotationDegrees;
+    }
+
+    /**
+     * Gets whether the buffer needs to be horizontally mirrored based on {@link UseCase} config.
+     */
+    public boolean getMirroring() {
+        return mMirroring;
+    }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEffectNode.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEffectNode.java
new file mode 100644
index 0000000..c0a10eb
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceEffectNode.java
@@ -0,0 +1,88 @@
+/*
+ * 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.camera.core.processing;
+
+import androidx.annotation.MainThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.camera.core.SurfaceEffect;
+import androidx.camera.core.impl.utils.Threads;
+import androidx.core.util.Preconditions;
+
+import java.util.Collections;
+import java.util.concurrent.Executor;
+
+/**
+ * A {@link Node} implementation that wraps around the public {@link SurfaceEffect} interface.
+ *
+ * <p>Responsibilities:
+ * <ul>
+ * <li>Calculating transformation and passing it to the {@link SurfaceEffect}.
+ * <li>Tracking the state of previously calculate specification and only recreate the pipeline
+ * when necessary.
+ * </ul>
+ */
+@RequiresApi(api = 21)
+// TODO(b/233627260): remove once implemented.
+@SuppressWarnings("UnusedVariable")
+public class SurfaceEffectNode implements Node<SurfaceIn, SurfaceOut> {
+    private final SurfaceEffect mSurfaceEffect;
+    private final Executor mExecutor;
+    // TODO(b/233680187): keep track of the state of the node so that the pipeline can be
+    //  recreated without restarting.
+    private SurfaceIn mSurfaceIn;
+    private SurfaceOut mSurfaceOut;
+    /**
+     * @param surfaceEffect the interface to wrap around.
+     * @param executor      the executor on which the {@link SurfaceEffect} methods are invoked.
+     */
+    public SurfaceEffectNode(@NonNull SurfaceEffect surfaceEffect, @NonNull Executor executor) {
+        mSurfaceEffect = surfaceEffect;
+        mExecutor = executor;
+    }
+    /**
+     * {@inheritDoc}
+     */
+    @Nullable
+    @Override
+    @MainThread
+    public SurfaceOut transform(@NonNull SurfaceIn surfaceIn) {
+        Threads.checkMainThread();
+        SettableSurface inputSurface = surfaceIn.getSurface();
+        // TODO(b/233627260): invoke mSurfaceEffect#onInputSurface with the value of inputSurface.
+        Preconditions.checkState(surfaceIn.getOutputOptions().size() == 1);
+        SurfaceOption surfaceOption = surfaceIn.getOutputOptions().get(0);
+        // TODO(b/233628734): calculate SurfaceInfo and outputSurface based on inputSurface and
+        //  outputOption.
+        // No transform output as placeholder. The correct outputSurface needs to be calculated
+        // based on inputSurface and outputOption.
+        SettableSurface outputSurface = new SettableSurface(
+                inputSurface.getTargets(),
+                inputSurface.getSize(),
+                inputSurface.getFormat(),
+                inputSurface.getSensorToBufferTransform(),
+                // TODO(b/233628734): the hasEmbeddedTransform value should be false, as
+                //  buffer-copying always removes the value.
+                inputSurface.hasEmbeddedTransform(),
+                inputSurface.getCropRect(),
+                inputSurface.getRotationDegrees(),
+                inputSurface.getMirroring());
+        // TODO(b/233627260): invoke mSurfaceEffect#onOutput with the value of outputSurface.
+        return SurfaceOut.create(Collections.singletonList(outputSurface));
+    }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceIn.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceIn.java
new file mode 100644
index 0000000..b96bd47
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceIn.java
@@ -0,0 +1,56 @@
+/*
+ * 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.camera.core.processing;
+
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.List;
+
+/**
+ * A data class represents a {@link Node} input that is based on {@link Surface}s.
+ */
+@AutoValue
+public abstract class SurfaceIn {
+
+    /**
+     * Instruction on how the buffer should be edited by the {@link Node}, one for each output.
+     *
+     * TODO(b/234180399): consider switching to com.google.common.collect.ImmutableList.
+     */
+    @SuppressWarnings("AutoValueImmutableFields")
+    @NonNull
+    public abstract List<SurfaceOption> getOutputOptions();
+
+    /**
+     * The input surface to read the frame from.
+     */
+    @NonNull
+    public abstract SettableSurface getSurface();
+
+    /**
+     * Creates an instance of {@link SurfaceIn}.
+     */
+    @NonNull
+    public static SurfaceIn create(@NonNull List<SurfaceOption> surfaceOptions,
+            @NonNull SettableSurface surface) {
+        return new AutoValue_SurfaceIn(surfaceOptions, surface);
+    }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOption.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOption.java
new file mode 100644
index 0000000..cb710bd
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOption.java
@@ -0,0 +1,85 @@
+/*
+ * 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.camera.core.processing;
+
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.camera.core.Preview;
+
+import com.google.auto.value.AutoValue;
+
+/**
+ * Options for how to produce a {@link SurfaceOut}.
+ */
+@AutoValue
+public abstract class SurfaceOption {
+
+    /**
+     * The container class of the target.
+     *
+     * e.g. {@link Preview} or {@link android.media.MediaCodec}.
+     */
+    @NonNull
+    public abstract Class<?> getTarget();
+
+    /**
+     * The format of the output {@link Surface}.
+     *
+     * <p> For GPU processing, it's always {@link ImageFormat#PRIVATE}.
+     */
+    public abstract int getFormat();
+
+    // Below are transformation need to be performed by the implementer of the node.
+
+    /**
+     * Gets the crop rect.
+     */
+    @NonNull
+    public abstract Rect getCropRect();
+
+    /**
+     * Gets the clockwise rotation degrees.
+     */
+    public abstract int getRotationDegrees();
+
+    /**
+     * Gets whether the buffer needs to be horizontally mirrored.
+     */
+    public abstract boolean getMirroring();
+
+    /**
+     * The target output size *after* the crop rect and rotation are applied.
+     */
+    @NonNull
+    public abstract Size getSize();
+
+    // Static utility method for creating instance.
+
+    /**
+     * Creates an instance of {@link SurfaceOption}.
+     */
+    @NonNull
+    public static SurfaceOption create(@NonNull Class<?> target, int format,
+            @NonNull Rect cropRect, int rotationDegrees, boolean mirroring, @NonNull Size size) {
+        return new AutoValue_SurfaceOption(target, format, cropRect, rotationDegrees,
+                mirroring, size);
+    }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOut.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOut.java
new file mode 100644
index 0000000..fce7dc0
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOut.java
@@ -0,0 +1,49 @@
+/*
+ * 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.camera.core.processing;
+
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.List;
+
+/**
+ * A data class represents a {@link Node} output that is based on {@link Surface}s.
+ */
+@AutoValue
+public abstract class SurfaceOut {
+
+    /**
+     * Gets output surfaces.
+     *
+     * TODO(b/234180399): consider switching to com.google.common.collect.ImmutableList.
+     */
+    @SuppressWarnings("AutoValueImmutableFields")
+    @NonNull
+    public abstract List<SettableSurface> getSurfaces();
+
+    /**
+     * Creates a {@link SurfaceOut}.
+     */
+    @NonNull
+    public static SurfaceOut create(@NonNull List<SettableSurface> surfaces) {
+        return new AutoValue_SurfaceOut(surfaces);
+    }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOutputImpl.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOutputImpl.java
new file mode 100644
index 0000000..485eed7c
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOutputImpl.java
@@ -0,0 +1,199 @@
+/*
+ * 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.camera.core.processing;
+
+import android.opengl.Matrix;
+import android.util.Size;
+import android.view.Surface;
+
+import androidx.annotation.AnyThread;
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.camera.core.Logger;
+import androidx.camera.core.SurfaceEffect;
+import androidx.camera.core.SurfaceOutput;
+import androidx.camera.core.impl.DeferrableSurface;
+import androidx.core.util.Preconditions;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+
+/**
+ * A implementation of {@link SurfaceOutput} that wraps a {@link SettableSurface}.
+ */
+@RequiresApi(21)
+public final class SurfaceOutputImpl implements SurfaceOutput {
+
+    private static final String TAG = "SurfaceOutputImpl";
+
+    private final Object mLock = new Object();
+
+    @NonNull
+    private final Surface mSurface;
+    @NonNull
+    private final SettableSurface mSettableSurface;
+
+    @NonNull
+    private final float[] mAdditionalTransform;
+
+    @GuardedBy("mLock")
+    @Nullable
+    private OnCloseRequestedListener mOnCloseRequestedListener;
+    @GuardedBy("mLock")
+    @Nullable
+    private Executor mExecutor;
+    @GuardedBy("mLock")
+    private boolean mHasPendingCloseRequest = false;
+    @GuardedBy("mLock")
+    private boolean mIsClosed = false;
+
+    /**
+     * @param settableSurface the state of settableSurface.getSurface() must be complete at the
+     *                        time of calling.
+     */
+    public SurfaceOutputImpl(
+            @NonNull SettableSurface settableSurface,
+            @NonNull float[] additionalTransform)
+            throws ExecutionException, InterruptedException,
+            DeferrableSurface.SurfaceClosedException {
+        mSettableSurface = settableSurface;
+        Preconditions.checkState(settableSurface.getSurface().isDone());
+        mSurface = settableSurface.getSurface().get();
+        mSettableSurface.incrementUseCount();
+        mAdditionalTransform = new float[16];
+        System.arraycopy(additionalTransform, 0, mAdditionalTransform, 0,
+                additionalTransform.length);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    @Override
+    @NonNull
+    public Surface getSurface(@NonNull Executor executor,
+            @NonNull OnCloseRequestedListener listener) {
+        boolean hasPendingCloseRequest;
+        synchronized (mLock) {
+            mExecutor = executor;
+            mOnCloseRequestedListener = listener;
+            hasPendingCloseRequest = mHasPendingCloseRequest;
+        }
+        if (hasPendingCloseRequest) {
+            requestClose();
+        }
+        return mSurface;
+    }
+
+    /**
+     * Asks the {@link SurfaceEffect} implementation to stopping writing to the {@link Surface}.
+     */
+    public void requestClose() {
+        OnCloseRequestedListener onCloseRequestedListener = null;
+        Executor executor = null;
+        synchronized (mLock) {
+            if (mExecutor == null || mOnCloseRequestedListener == null) {
+                // If close is requested but not executed because of missing listener, set a flag so
+                // we can execute it when the listener is et.
+                mHasPendingCloseRequest = true;
+            } else if (!mIsClosed) {
+                onCloseRequestedListener = mOnCloseRequestedListener;
+                executor = mExecutor;
+                mHasPendingCloseRequest = false;
+            }
+        }
+        if (executor != null) {
+            try {
+                executor.execute(onCloseRequestedListener::onCloseRequested);
+            } catch (RejectedExecutionException e) {
+                // The executor might be invoked after the SurfaceOutputImpl is closed. This
+                // happens if the #close() is called after the synchronized block above but
+                // before the line below.
+                Logger.d(TAG, "Effect executor closed. Close request not posted.", e);
+            }
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    @Override
+    public int getTargets() {
+        return mSettableSurface.getTargets();
+    }
+
+    /**
+     * @inheritDoc
+     */
+    @Override
+    @NonNull
+    public Size getSize() {
+        return mSettableSurface.getSize();
+    }
+
+    /**
+     * @inheritDoc
+     */
+    @Override
+    public int getFormat() {
+        return mSettableSurface.getFormat();
+    }
+
+    /**
+     * This method can be invoked by the effect implementation on any thread.
+     *
+     * @inheritDoc
+     */
+    @AnyThread
+    @Override
+    public void close() {
+        synchronized (mLock) {
+            if (mIsClosed) {
+                // Return early if it's already closed.
+                return;
+            } else {
+                mIsClosed = true;
+            }
+        }
+        mSettableSurface.decrementUseCount();
+    }
+
+    /**
+     * Returns the close state.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.TESTS)
+    public boolean isClosed() {
+        synchronized (mLock) {
+            return mIsClosed;
+        }
+    }
+
+    /**
+     * This method can be invoked by the effect implementation on any thread.
+     */
+    @AnyThread
+    @Override
+    public void updateTransformMatrix(@NonNull float[] updated, @NonNull float[] original) {
+        Matrix.multiplyMM(updated, 0, mAdditionalTransform, 0, original, 0);
+    }
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/package-info.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/package-info.java
new file mode 100644
index 0000000..16dc03e
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ * 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.
+ */
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+package androidx.camera.core.processing;
+
+import androidx.annotation.RestrictTo;
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
index bdce064..9cb4ec3e 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
@@ -30,6 +30,7 @@
 import android.view.Surface;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.camera.core.impl.CameraFactory;
 import androidx.camera.core.impl.CameraInternal;
 import androidx.camera.core.impl.ImageAnalysisConfig;
@@ -72,6 +73,9 @@
 @Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
 public class ImageAnalysisTest {
 
+    private static final Size APP_RESOLUTION = new Size(100, 200);
+    private static final Size ANALYZER_RESOLUTION = new Size(300, 400);
+
     private static final int QUEUE_DEPTH = 8;
     private static final int IMAGE_TAG = 0;
     private static final long TIMESTAMP_1 = 1;
@@ -135,15 +139,33 @@
     }
 
     @Test
-    public void setAnalyzerWithResolution_overridesUseCaseResolution() {
+    public void setAnalyzerWithResolution_doesNotOverridesUseCaseResolution() {
+        assertThat(getMergedAnalyzerResolution(APP_RESOLUTION, ANALYZER_RESOLUTION)).isEqualTo(
+                APP_RESOLUTION);
+    }
+
+    @Test
+    public void setAnalyzerWithResolution_usedAsDefaultUseCaseResolution() {
+        assertThat(getMergedAnalyzerResolution(null, ANALYZER_RESOLUTION)).isEqualTo(
+                ANALYZER_RESOLUTION);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void noAppOrAnalyzerResolution_noMergedOption() {
+        getMergedAnalyzerResolution(null, null);
+    }
+
+    @NonNull
+    private Size getMergedAnalyzerResolution(
+            @Nullable Size appResolution,
+            @Nullable Size analyzerResolution) {
         // Arrange: set up ImageAnalysis with target resolution.
-        Size appResolution = new Size(100, 200);
-        ImageAnalysis.Builder builder =
-                new ImageAnalysis.Builder().setTargetResolution(appResolution).setImageQueueDepth(
-                        QUEUE_DEPTH);
+        ImageAnalysis.Builder builder = new ImageAnalysis.Builder().setImageQueueDepth(QUEUE_DEPTH);
+        if (appResolution != null) {
+            builder.setTargetResolution(appResolution);
+        }
         mImageAnalysis = builder.build();
         // Analyzer that overrides the resolution.
-        Size analyzerResolution = new Size(300, 400);
         ImageAnalysis.Analyzer analyzer = new ImageAnalysis.Analyzer() {
             @Override
             public void analyze(@NonNull ImageProxy image) {
@@ -151,7 +173,7 @@
             }
 
             @Override
-            public Size getTargetResolutionOverride() {
+            public Size getDefaultTargetResolution() {
                 return analyzerResolution;
             }
         };
@@ -162,8 +184,9 @@
         // Assert: only the target resolution is overridden.
         ImageAnalysisConfig mergedConfig = (ImageAnalysisConfig) mImageAnalysis.mergeConfigs(
                 new FakeCameraInfoInternal(), null, null);
-        assertThat(mergedConfig.getTargetResolution()).isEqualTo(analyzerResolution);
+
         assertThat(mergedConfig.getImageQueueDepth()).isEqualTo(QUEUE_DEPTH);
+        return mergedConfig.getTargetResolution();
     }
 
     @Test
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/processing/SettableSurfaceTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/processing/SettableSurfaceTest.kt
new file mode 100644
index 0000000..55adf79
--- /dev/null
+++ b/camera/camera-core/src/test/java/androidx/camera/core/processing/SettableSurfaceTest.kt
@@ -0,0 +1,123 @@
+/*
+ * 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.camera.core.processing
+
+import android.graphics.ImageFormat
+import android.graphics.Matrix
+import android.graphics.Rect
+import android.graphics.SurfaceTexture
+import android.os.Build
+import android.util.Size
+import android.view.Surface
+import androidx.camera.core.impl.DeferrableSurface
+import androidx.camera.core.impl.utils.executor.CameraXExecutors
+import androidx.camera.core.impl.utils.futures.Futures
+import androidx.camera.core.SurfaceOutput
+import androidx.camera.testing.fakes.FakeCamera
+import com.google.common.truth.Truth
+import com.google.common.util.concurrent.ListenableFuture
+import java.util.concurrent.ExecutionException
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+
+/**
+ * Unit tests for [SettableSurface].
+ */
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class SettableSurfaceTest {
+    private lateinit var fakeDeferrableSurface: DeferrableSurface
+    private lateinit var fakeSettableSurface: SettableSurface
+
+    @Before
+    fun setUp() {
+        fakeDeferrableSurface = createFakeDeferrableSurface()
+        fakeSettableSurface = createFakeSettableSurface()
+    }
+
+    @After
+    fun tearDown() {
+        fakeDeferrableSurface.close()
+        fakeSettableSurface.close()
+    }
+
+    @Test
+    @Throws(ExecutionException::class, InterruptedException::class)
+    fun setSource_surfaceIsPropagated() {
+        // Act.
+        fakeSettableSurface.setSource(fakeDeferrableSurface)
+        // Assert.
+        Truth.assertThat(fakeSettableSurface.surface.get())
+            .isEqualTo(fakeDeferrableSurface.surface.get())
+    }
+
+    @Test
+    @Throws(ExecutionException::class, InterruptedException::class)
+    fun createSurfaceRequestAsSource_surfaceIsPropagated() {
+        // Act.
+        val surfaceRequest = fakeSettableSurface.createSurfaceRequestAsSource(
+            FakeCamera(), false
+        )
+        surfaceRequest.provideSurface(
+            fakeDeferrableSurface.surface.get(),
+            CameraXExecutors.directExecutor()
+        ) { fakeDeferrableSurface.close() }
+        // Assert.
+        Truth.assertThat(fakeSettableSurface.surface.get())
+            .isEqualTo(fakeDeferrableSurface.surface.get())
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun setSourceTwice_throwsException() {
+        fakeSettableSurface.setSource(fakeDeferrableSurface)
+        fakeSettableSurface.setSource(fakeDeferrableSurface)
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun setSourceThenCreateSurfaceRequest_throwsException() {
+        fakeSettableSurface.setSource(fakeDeferrableSurface)
+        fakeSettableSurface.createSurfaceRequestAsSource(FakeCamera(), false)
+    }
+
+    private fun createFakeSettableSurface(): SettableSurface {
+        return SettableSurface(
+            SurfaceOutput.PREVIEW, Size(640, 480), ImageFormat.PRIVATE,
+            Matrix(), true, Rect(), 0, false
+        )
+    }
+
+    private fun createFakeDeferrableSurface(): DeferrableSurface {
+        val surfaceTexture = SurfaceTexture(0)
+        val surface = Surface(surfaceTexture)
+        val deferrableSurface = object : DeferrableSurface() {
+            override fun provideSurface(): ListenableFuture<Surface> {
+                return Futures.immediateFuture(surface)
+            }
+        }
+        deferrableSurface.terminationFuture.addListener({
+            surface.release()
+            surfaceTexture.release()
+        }, CameraXExecutors.directExecutor())
+        return deferrableSurface
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt
new file mode 100644
index 0000000..b210b47
--- /dev/null
+++ b/camera/camera-core/src/test/java/androidx/camera/core/processing/SurfaceOutputImplTest.kt
@@ -0,0 +1,176 @@
+/*
+ * 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.camera.core.processing
+
+import android.graphics.ImageFormat
+import android.graphics.Rect
+import android.graphics.SurfaceTexture
+import android.opengl.Matrix
+import android.os.Build
+import android.os.Looper
+import android.util.Size
+import android.view.Surface
+import androidx.camera.core.SurfaceOutput
+import androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.Shadows.shadowOf
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+
+/**
+ * Unit tests for [SurfaceOutputImpl].
+ */
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class SurfaceOutputImplTest {
+
+    companion object {
+        private val IDENTITY_MATRIX = FloatArray(16).apply {
+            Matrix.setIdentityM(this, 0)
+        }
+        private const val FLOAT_TOLERANCE = 1E-4
+    }
+
+    lateinit var fakeSurface: Surface
+    lateinit var fakeSurfaceTexture: SurfaceTexture
+    private val surfacesToCleanup = mutableListOf<SettableSurface>()
+    private val surfaceOutputsToCleanup = mutableListOf<SurfaceOutputImpl>()
+
+    @Before
+    fun setUp() {
+        fakeSurfaceTexture = SurfaceTexture(0)
+        fakeSurface = Surface(fakeSurfaceTexture)
+    }
+
+    @After
+    fun tearDown() {
+        fakeSurfaceTexture.release()
+        fakeSurface.release()
+        surfacesToCleanup.forEach {
+            it.close()
+        }
+        surfaceOutputsToCleanup.forEach {
+            it.close()
+        }
+    }
+
+    @Test(expected = java.lang.IllegalStateException::class)
+    fun createWithIncompleteFuture_throwsException() {
+        createFakeSurfaceOutputImpl(settableSurface = createIncompleteSettableSurface())
+    }
+
+    @Test
+    fun requestClose_receivesOnCloseRequested() {
+        // Arrange.
+        val surfaceOutImpl = createFakeSurfaceOutputImpl()
+        var hasRequestedClose = false
+        surfaceOutImpl.getSurface(mainThreadExecutor()) {
+            hasRequestedClose = true
+        }
+        // Act.
+        surfaceOutImpl.requestClose()
+        shadowOf(Looper.getMainLooper()).idle()
+        // Assert.
+        assertThat(hasRequestedClose).isTrue()
+    }
+
+    @Test
+    fun closedSurface_noLongerReceivesCloseRequest() {
+        // Arrange.
+        val surfaceOutImpl = createFakeSurfaceOutputImpl()
+        var hasRequestedClose = false
+        surfaceOutImpl.getSurface(mainThreadExecutor()) {
+            hasRequestedClose = true
+        }
+
+        // Act.
+        surfaceOutImpl.close()
+        surfaceOutImpl.requestClose()
+        shadowOf(Looper.getMainLooper()).idle()
+
+        // Assert.
+        assertThat(hasRequestedClose).isFalse()
+    }
+
+    @Test
+    fun updateMatrix_multipliesMatrices() {
+        // Arrange.
+        // 2x scaling on the x axis.
+        val scale2x = FloatArray(16).apply {
+            Matrix.setIdentityM(this, 0)
+            Matrix.scaleM(this, 0, 2F, 1F, 1F)
+        }
+        val surfaceOut = createFakeSurfaceOutputImpl(transform = scale2x)
+
+        // Act: apply the 2x scaling on top of the 90° rotation.
+        // 90° clockwise rotation around (0, 0).
+        val rotate90 = FloatArray(16).apply {
+            Matrix.setRotateM(this, 0, 90F, 0F, 0F, -1F)
+        }
+        val result = FloatArray(16)
+        surfaceOut.updateTransformMatrix(result, rotate90)
+
+        // Assert.
+        // Assert the result is a multiplication of the two matrices.
+        val expectedMatrix = FloatArray(16).apply {
+            Matrix.multiplyMM(this, 0, scale2x, 0, rotate90, 0)
+        }
+        assertThat(result).usingTolerance(FLOAT_TOLERANCE).containsExactly(expectedMatrix)
+
+        // Assert coordinates mapping is correct.
+        //       90° rotation         2x scaling on the X axis
+        // (1,1) -------------> (1,-1) ----------------------> (2,-1)
+        val point = floatArrayOf(1F, 1F, 0F, 1F)
+        val expectedPoint = FloatArray(4)
+        Matrix.multiplyMV(expectedPoint, 0, result, 0, point, 0)
+        assertThat(expectedPoint).usingTolerance(FLOAT_TOLERANCE)
+            .containsExactly(floatArrayOf(2F, -1F, 0F, 1F))
+    }
+
+    private fun createCompleteSettableSurface(): SettableSurface {
+        return createFakeSettableSurface(true)
+    }
+
+    private fun createIncompleteSettableSurface(): SettableSurface {
+        return createFakeSettableSurface(false)
+    }
+
+    private fun createFakeSettableSurface(setComplete: Boolean): SettableSurface {
+        val settableSurface = SettableSurface(
+            SurfaceOutput.PREVIEW, Size(640, 480), ImageFormat.PRIVATE,
+            android.graphics.Matrix(), true, Rect(), 0, false
+        )
+        if (setComplete) {
+            settableSurface.mCompleter.set(fakeSurface)
+        }
+        surfacesToCleanup.add(settableSurface)
+        return settableSurface
+    }
+
+    private fun createFakeSurfaceOutputImpl(
+        settableSurface: SettableSurface = createCompleteSettableSurface(),
+        transform: FloatArray = IDENTITY_MATRIX
+    ) = SurfaceOutputImpl(settableSurface, transform).apply {
+        surfaceOutputsToCleanup.add(this)
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-effects/build.gradle b/camera/camera-effects/build.gradle
index e82c7eb..ce77c26 100644
--- a/camera/camera-effects/build.gradle
+++ b/camera/camera-effects/build.gradle
@@ -29,6 +29,7 @@
         multiDexEnabled = true
     }
     testOptions.unitTests.includeAndroidResources = true
+    namespace "androidx.camera.effects"
 }
 androidx {
     name = "Jetpack Camera Effects Library"
diff --git a/camera/camera-effects/src/main/AndroidManifest.xml b/camera/camera-effects/src/main/AndroidManifest.xml
deleted file mode 100644
index f0be73e..0000000
--- a/camera/camera-effects/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  -->
-
-<manifest package="androidx.camera.effects"/>
\ No newline at end of file
diff --git a/camera/camera-extensions-stub/lint-baseline.xml b/camera/camera-extensions-stub/lint-baseline.xml
index cd2b316..879b407 100644
--- a/camera/camera-extensions-stub/lint-baseline.xml
+++ b/camera/camera-extensions-stub/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
@@ -625,15 +625,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void process(Map&lt;Integer, Pair&lt;Image, TotalCaptureResult>> results);"
-        errorLine2="                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    List&lt;Pair&lt;CaptureRequest.Key, Object>> getParameters();"
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -922,60 +913,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    boolean isExtensionAvailable(String cameraId, CameraCharacteristics cameraCharacteristics);"
-        errorLine2="                                 ~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    boolean isExtensionAvailable(String cameraId, CameraCharacteristics cameraCharacteristics);"
-        errorLine2="                                                  ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void init(String cameraId, CameraCharacteristics cameraCharacteristics);"
-        errorLine2="              ~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void init(String cameraId, CameraCharacteristics cameraCharacteristics);"
-        errorLine2="                               ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    CaptureProcessorImpl getCaptureProcessor();"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    List&lt;CaptureStageImpl> getCaptureStages();"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
         errorLine2="                     ~~~~~~">
         <location
@@ -1246,24 +1183,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void process(Image image, TotalCaptureResult result);"
-        errorLine2="                 ~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void process(Image image, TotalCaptureResult result);"
-        errorLine2="                              ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    void onOutputSurface(Surface surface, int imageFormat);"
         errorLine2="                         ~~~~~~~">
         <location
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
index ccb0dac..514ca3b 100755
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
@@ -45,15 +45,18 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureProcessorImpl getCaptureProcessor() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<CaptureStageImpl> getCaptureStages() {
         throw new RuntimeException("Stub, replace with implementation.");
@@ -65,8 +68,9 @@
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
@@ -75,21 +79,25 @@
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         throw new RuntimeException("Stub, replace with implementation.");
@@ -97,17 +105,17 @@
 
     @Nullable
     @Override
-    public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+    public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
-    @Nullable
+    @NonNull
     @Override
     public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
-    @Nullable
+    @NonNull
     @Override
     public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
         throw new RuntimeException("Stub, replace with implementation.");
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
index 100f665..85b63df 100755
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
@@ -44,28 +44,33 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @NonNull
     @Override
     public CaptureStageImpl getCaptureStage() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @NonNull
     @Override
     public ProcessorType getProcessorType() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public ProcessorImpl getProcessor() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
@@ -74,21 +79,25 @@
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         throw new RuntimeException("Stub, replace with implementation.");
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
index 2d26639..c547f772 100755
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
@@ -45,15 +45,18 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureProcessorImpl getCaptureProcessor() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<CaptureStageImpl> getCaptureStages() {
         throw new RuntimeException("Stub, replace with implementation.");
@@ -65,8 +68,9 @@
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
@@ -75,21 +79,25 @@
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         throw new RuntimeException("Stub, replace with implementation.");
@@ -97,17 +105,17 @@
 
     @Nullable
     @Override
-    public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+    public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
-    @Nullable
+    @NonNull
     @Override
     public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
-    @Nullable
+    @NonNull
     @Override
     public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
         throw new RuntimeException("Stub, replace with implementation.");
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
index bc3e48d..da5748c 100755
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
@@ -44,28 +44,33 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @NonNull
     @Override
     public CaptureStageImpl getCaptureStage() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @NonNull
     @Override
     public ProcessorType getProcessorType() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public ProcessorImpl getProcessor() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
@@ -74,21 +79,25 @@
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         throw new RuntimeException("Stub, replace with implementation.");
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
index 66c5839d..74d50b1 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
@@ -45,15 +45,18 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureProcessorImpl getCaptureProcessor() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<CaptureStageImpl> getCaptureStages() {
         throw new RuntimeException("Stub, replace with implementation.");
@@ -65,8 +68,9 @@
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
@@ -75,21 +79,25 @@
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         throw new RuntimeException("Stub, replace with implementation.");
@@ -97,17 +105,17 @@
 
     @Nullable
     @Override
-    public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+    public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
-    @Nullable
+    @NonNull
     @Override
     public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
-    @Nullable
+    @NonNull
     @Override
     public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
         throw new RuntimeException("Stub, replace with implementation.");
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
index ff58862..6083103 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
@@ -42,28 +42,33 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @NonNull
     @Override
     public CaptureStageImpl getCaptureStage() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @NonNull
     @Override
     public ProcessorType getProcessorType() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public ProcessorImpl getProcessor() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
@@ -72,21 +77,25 @@
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         throw new RuntimeException("Stub, replace with implementation.");
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/CaptureStageImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/CaptureStageImpl.java
index c4796c2..c4f4a47 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/CaptureStageImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/CaptureStageImpl.java
@@ -19,6 +19,8 @@
 import android.hardware.camera2.CaptureRequest;
 import android.util.Pair;
 
+import androidx.annotation.NonNull;
+
 import java.util.List;
 
 /**
@@ -34,5 +36,6 @@
      * Returns the set of {@link CaptureRequest.Key} and the corresponding values that will be
      * set for a single {@link CaptureRequest}.
      */
+    @NonNull
     List<Pair<CaptureRequest.Key, Object>> getParameters();
 }
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java
index 2879568..a74a880 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java
@@ -17,11 +17,15 @@
 package androidx.camera.extensions.impl;
 
 import android.content.Context;
+import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.params.SessionConfiguration;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 /**
  * Provides interfaces that the OEM needs to implement to handle the state change.
  *
@@ -39,7 +43,8 @@
      * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
      * @param context The {@link Context} used for CameraX.
      */
-    void onInit(String cameraId, CameraCharacteristics cameraCharacteristics, Context context);
+    void onInit(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context);
 
     /**
      * Notify to de-initialize the extension. This callback will be invoked after unbind.
@@ -50,7 +55,7 @@
 
     /**
      * This will be invoked before creating a
-     * {@link android.hardware.camera2.CameraCaptureSession}. The {@link CaptureRequest}
+     * {@link CameraCaptureSession}. The {@link CaptureRequest}
      * parameters returned via {@link CaptureStageImpl} will be passed to the camera device as
      * part of the capture session initialization via
      * {@link SessionConfiguration#setSessionParameters(CaptureRequest)} which only supported from
@@ -58,10 +63,11 @@
      *
      * @return The request information to set the session wide camera parameters.
      */
+    @Nullable
     CaptureStageImpl onPresetSession();
 
     /**
-     * This will be invoked once after the {@link android.hardware.camera2.CameraCaptureSession}
+     * This will be invoked once after the {@link CameraCaptureSession}
      * has been created. The {@link CaptureRequest} parameters returned via
      * {@link CaptureStageImpl} will be used to generate a single request to the current
      * configured {@link CameraDevice}. The generated request will be submitted to camera before
@@ -69,15 +75,17 @@
      *
      * @return The request information to create a single capture request to camera device.
      */
+    @Nullable
     CaptureStageImpl onEnableSession();
 
     /**
-     * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is
+     * This will be invoked before the {@link CameraCaptureSession} is
      * closed. The {@link CaptureRequest} parameters returned via {@link CaptureStageImpl} will
      * be used to generate a single request to the currently configured {@link CameraDevice}. The
      * generated request will be submitted to camera before the CameraCaptureSession is closed.
      *
      * @return The request information to customize the session.
      */
+    @Nullable
     CaptureStageImpl onDisableSession();
 }
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
index 7769551..e20ea0d 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
@@ -16,6 +16,8 @@
 
 package androidx.camera.extensions.impl;
 
+import androidx.annotation.NonNull;
+
 /**
  * Stub implementation for the extension version check.
  *
@@ -50,7 +52,9 @@
      * @return the version that vendor supported in this device. The MAJOR.MINOR.PATCH format
      * should be used.
      */
-    public String checkApiVersion(String version) {
+    @SuppressWarnings("unused")
+    @NonNull
+    public String checkApiVersion(@NonNull String version) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
index f1191dcf..507f214 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
@@ -45,15 +45,18 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureProcessorImpl getCaptureProcessor() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<CaptureStageImpl> getCaptureStages() {
         throw new RuntimeException("Stub, replace with implementation.");
@@ -65,8 +68,9 @@
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
@@ -75,21 +79,25 @@
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         throw new RuntimeException("Stub, replace with implementation.");
@@ -97,17 +105,17 @@
 
     @Nullable
     @Override
-    public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+    public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
-    @Nullable
+    @NonNull
     @Override
     public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
-    @Nullable
+    @NonNull
     @Override
     public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
         throw new RuntimeException("Stub, replace with implementation.");
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
index 0eb4a61..83f1a34 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
@@ -44,28 +44,33 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @NonNull
     @Override
     public CaptureStageImpl getCaptureStage() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @NonNull
     @Override
     public ProcessorType getProcessorType() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public ProcessorImpl getProcessor() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
@@ -74,21 +79,25 @@
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         throw new RuntimeException("Stub, replace with implementation.");
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
index 88bd105..10b4513 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
@@ -16,15 +16,18 @@
 
 package androidx.camera.extensions.impl;
 
-import android.annotation.SuppressLint;
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
 import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import java.util.List;
 
 /**
@@ -32,7 +35,6 @@
  *
  * @since 1.0
  */
-@SuppressLint("UnknownNullness")
 public interface ImageCaptureExtenderImpl extends ExtenderStateListener {
     /**
      * Indicates whether the extension is supported on the device.
@@ -41,7 +43,8 @@
      * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
      * @return true if the extension is supported, otherwise false
      */
-    boolean isExtensionAvailable(String cameraId, CameraCharacteristics cameraCharacteristics);
+    boolean isExtensionAvailable(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics);
 
     /**
      * Initializes the extender to be used with the specified camera.
@@ -52,14 +55,16 @@
      * @param cameraId The camera2 id string of the camera.
      * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
      */
-    void init(String cameraId, CameraCharacteristics cameraCharacteristics);
+    void init(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics);
 
     /**
      * The processing that will be done on a set of captures to create and image with the effect.
      */
+    @Nullable
     CaptureProcessorImpl getCaptureProcessor();
 
     /** The set of captures that are needed to create an image with the effect. */
+    @Nullable
     List<CaptureStageImpl> getCaptureStages();
 
     /**
@@ -74,14 +79,15 @@
      * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned.
      *
      * <p>The returned resolutions should be subset of the supported sizes retrieved from
-     * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device. If the
+     * {@link StreamConfigurationMap} for the camera device. If the
      * returned list is not null, it will be used to find the best resolutions combination for
      * the bound use cases.
      *
      * @return the customized supported resolutions, or null to support all sizes retrieved from
-     *         {@link android.hardware.camera2.params.StreamConfigurationMap}.
+     * {@link StreamConfigurationMap}.
      * @since 1.1
      */
+    @Nullable
     List<Pair<Integer, Size[]>> getSupportedResolutions();
 
     /**
@@ -98,7 +104,8 @@
      * null if no capture latency info can be provided.
      * @since 1.2
      */
-    Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize);
+    @Nullable
+    Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize);
 
     /**
      * Return a list of orthogonal capture request keys.
@@ -139,6 +146,7 @@
      * are not supported.
      * @since 1.3
      */
+    @NonNull
     List<CaptureRequest.Key> getAvailableCaptureRequestKeys();
 
     /**
@@ -158,5 +166,6 @@
      * supported.
      * @since 1.3
      */
+    @NonNull
     List<CaptureResult.Key> getAvailableCaptureResultKeys();
 }
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
index c8ac978..05a195e 100755
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
@@ -45,15 +45,18 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureProcessorImpl getCaptureProcessor() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<CaptureStageImpl> getCaptureStages() {
         throw new RuntimeException("Stub, replace with implementation.");
@@ -65,8 +68,9 @@
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
@@ -75,21 +79,25 @@
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         throw new RuntimeException("Stub, replace with implementation.");
@@ -97,17 +105,17 @@
 
     @Nullable
     @Override
-    public Range<Long> getEstimatedCaptureLatencyRange(@NonNull Size captureOutputSize) {
+    public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
-    @Nullable
+    @NonNull
     @Override
     public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
-    @Nullable
+    @NonNull
     @Override
     public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
         throw new RuntimeException("Stub, replace with implementation.");
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
index a5809f6..eeb254b 100755
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
@@ -44,28 +44,33 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @NonNull
     @Override
     public CaptureStageImpl getCaptureStage() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @NonNull
     @Override
     public ProcessorType getProcessorType() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public ProcessorImpl getProcessor() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
@@ -74,21 +79,25 @@
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         throw new RuntimeException("Stub, replace with implementation.");
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         throw new RuntimeException("Stub, replace with implementation.");
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
index 4324987..b320813 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
@@ -18,10 +18,12 @@
 
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.TotalCaptureResult;
 import android.util.Pair;
 import android.util.Size;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import java.util.List;
@@ -49,7 +51,8 @@
      * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
      * @return true if the extension is supported, otherwise false
      */
-    boolean isExtensionAvailable(String cameraId, CameraCharacteristics cameraCharacteristics);
+    boolean isExtensionAvailable(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics);
 
     /**
      * Initializes the extender to be used with the specified camera.
@@ -60,22 +63,24 @@
      * @param cameraId The camera2 id string of the camera.
      * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
      */
-    void init(String cameraId, CameraCharacteristics cameraCharacteristics);
+    void init(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics);
 
     /**
      * The set of parameters required to produce the effect on the preview stream.
      *
      * <p> This will be the initial set of parameters used for the preview
-     * {@link android.hardware.camera2.CaptureRequest}. If the {@link ProcessorType} is defined as
+     * {@link CaptureRequest}. If the {@link ProcessorType} is defined as
      * {@link ProcessorType#PROCESSOR_TYPE_REQUEST_UPDATE_ONLY} then this will be updated when
      * the {@link RequestUpdateProcessorImpl#process(TotalCaptureResult)} from {@link
      * #getProcessor()} has been called, this should be updated to reflect the new {@link
      * CaptureStageImpl}. If the processing step returns a {@code null}, meaning the required
      * parameters has not changed, then calling this will return the previous non-null value.
      */
+    @NonNull
     CaptureStageImpl getCaptureStage();
 
     /** The type of preview processing to use. */
+    @NonNull
     ProcessorType getProcessorType();
 
     /**
@@ -91,6 +96,7 @@
      * <tr><td> PROCESSOR_TYPE_NONE </td> <td> null </td> </tr>
      * </table>
      */
+    @Nullable
     ProcessorImpl getProcessor();
 
     /**
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ProcessorImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ProcessorImpl.java
index 6be328b..e5ca19e 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ProcessorImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/ProcessorImpl.java
@@ -19,6 +19,8 @@
 import android.util.Size;
 import android.view.Surface;
 
+import androidx.annotation.NonNull;
+
 /**
  * Processes an input image stream and produces an output image stream.
  *
@@ -31,23 +33,23 @@
      * @param surface     The {@link Surface} that the ProcessorImpl should write data into.
      * @param imageFormat The format of that the surface expects.
      */
-    void onOutputSurface(Surface surface, int imageFormat);
+    void onOutputSurface(@NonNull Surface surface, int imageFormat);
 
     /**
      * Invoked when CameraX changes the configured output resolution.
      *
-     * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
-     * input to be at the specified resolution.
+     * <p>After this call, {@link CaptureProcessorImpl} should expect any
+     * {@link android.media.Image} received as input to be at the specified resolution.
      *
      * @param size for the surface.
      */
-    void onResolutionUpdate(Size size);
+    void onResolutionUpdate(@NonNull Size size);
 
     /**
      * Invoked when CameraX changes the configured input image format.
      *
-     * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
-     * input to have the specified image format.
+     * <p>After this call, {@link CaptureProcessorImpl} should expect any
+     * {@link android.media.Image} received as input to have the specified image format.
      *
      * @param imageFormat for the surface.
      */
diff --git a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
index 14637d7..ac3bfb3 100644
--- a/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
+++ b/camera/camera-extensions-stub/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
@@ -18,6 +18,8 @@
 
 import android.hardware.camera2.TotalCaptureResult;
 
+import androidx.annotation.Nullable;
+
 /**
  * Processes a {@link TotalCaptureResult} to update a CaptureStage.
  *
@@ -32,5 +34,6 @@
      * @return The updated parameters used for the repeating requests. If this is {@code null} then
      * the previous parameters will be used.
      */
-    CaptureStageImpl process(TotalCaptureResult result);
+    @Nullable
+    CaptureStageImpl process(@Nullable TotalCaptureResult result);
 }
diff --git a/camera/camera-extensions/lint-baseline.xml b/camera/camera-extensions/lint-baseline.xml
index 68643d2..382b9d2 100644
--- a/camera/camera-extensions/lint-baseline.xml
+++ b/camera/camera-extensions/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnsafeOptInUsageError"
diff --git a/camera/camera-mlkit-vision/api/current.txt b/camera/camera-mlkit-vision/api/current.txt
index 5456107..0599c25 100644
--- a/camera/camera-mlkit-vision/api/current.txt
+++ b/camera/camera-mlkit-vision/api/current.txt
@@ -4,8 +4,8 @@
   @RequiresApi(21) public class MlKitAnalyzer implements androidx.camera.core.ImageAnalysis.Analyzer {
     ctor public MlKitAnalyzer(java.util.List<com.google.mlkit.vision.interfaces.Detector<?>!>, int, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.mlkit.vision.MlKitAnalyzer.Result!>);
     method public final void analyze(androidx.camera.core.ImageProxy);
+    method public final android.util.Size getDefaultTargetResolution();
     method public final int getTargetCoordinateSystem();
-    method public final android.util.Size getTargetResolutionOverride();
     method public final void updateTransform(android.graphics.Matrix?);
   }
 
diff --git a/camera/camera-mlkit-vision/api/public_plus_experimental_current.txt b/camera/camera-mlkit-vision/api/public_plus_experimental_current.txt
index 5456107..0599c25 100644
--- a/camera/camera-mlkit-vision/api/public_plus_experimental_current.txt
+++ b/camera/camera-mlkit-vision/api/public_plus_experimental_current.txt
@@ -4,8 +4,8 @@
   @RequiresApi(21) public class MlKitAnalyzer implements androidx.camera.core.ImageAnalysis.Analyzer {
     ctor public MlKitAnalyzer(java.util.List<com.google.mlkit.vision.interfaces.Detector<?>!>, int, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.mlkit.vision.MlKitAnalyzer.Result!>);
     method public final void analyze(androidx.camera.core.ImageProxy);
+    method public final android.util.Size getDefaultTargetResolution();
     method public final int getTargetCoordinateSystem();
-    method public final android.util.Size getTargetResolutionOverride();
     method public final void updateTransform(android.graphics.Matrix?);
   }
 
diff --git a/camera/camera-mlkit-vision/api/restricted_current.txt b/camera/camera-mlkit-vision/api/restricted_current.txt
index 5456107..0599c25 100644
--- a/camera/camera-mlkit-vision/api/restricted_current.txt
+++ b/camera/camera-mlkit-vision/api/restricted_current.txt
@@ -4,8 +4,8 @@
   @RequiresApi(21) public class MlKitAnalyzer implements androidx.camera.core.ImageAnalysis.Analyzer {
     ctor public MlKitAnalyzer(java.util.List<com.google.mlkit.vision.interfaces.Detector<?>!>, int, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.mlkit.vision.MlKitAnalyzer.Result!>);
     method public final void analyze(androidx.camera.core.ImageProxy);
+    method public final android.util.Size getDefaultTargetResolution();
     method public final int getTargetCoordinateSystem();
-    method public final android.util.Size getTargetResolutionOverride();
     method public final void updateTransform(android.graphics.Matrix?);
   }
 
diff --git a/camera/camera-mlkit-vision/src/main/java/androidx/camera/mlkit/vision/MlKitAnalyzer.java b/camera/camera-mlkit-vision/src/main/java/androidx/camera/mlkit/vision/MlKitAnalyzer.java
index 66449f8..3ae7d6b 100644
--- a/camera/camera-mlkit-vision/src/main/java/androidx/camera/mlkit/vision/MlKitAnalyzer.java
+++ b/camera/camera-mlkit-vision/src/main/java/androidx/camera/mlkit/vision/MlKitAnalyzer.java
@@ -56,13 +56,19 @@
  * {@code Detector}s finish analyzing the frame, {@link Consumer#accept} will be
  * invoked with the aggregated analysis results.
  *
+ * <p> This class handles the coordinates transformation between MLKit output and the target
+ * coordinate system. Based the {@code targetCoordinateSystem} set in the constructor, it
+ * calculates the {@link Matrix} with the value provided by CameraX via
+ * {@link ImageAnalysis.Analyzer#updateTransform} and forward it to the MLKit {@code Detector}. The
+ * coordinates returned by MLKit will be in the desired coordinate system.
+ *
  * <p> This class is designed to work seamlessly with the {@code CameraController} class in
  * camera-view. When used with {@link ImageAnalysis} in camera-core, the following scenarios may
  * need special handling:
  * <ul>
  * <li> Cannot transform coordinates to UI coordinate system. e.g. camera-core only supports
  * {@link ImageAnalysis#COORDINATE_SYSTEM_ORIGINAL}.
- * <li>For the value of {@link #getTargetResolutionOverride()} to be effective, make sure
+ * <li>For the value of {@link #getDefaultTargetResolution()} to be effective, make sure
  * the {@link ImageAnalysis#setAnalyzer} is called before it's bound to the lifecycle.
  * </ul>
  *
@@ -112,6 +118,12 @@
      * {@code Detector#getDetectorType()} is TYPE_SEGMENTATION and {@code targetCoordinateSystem}
      * is COORDINATE_SYSTEM_ORIGINAL. Currently MLKit does not support transformation with
      * segmentation.
+     *
+     * @param detectors              list of MLKit {@link Detector}.
+     * @param targetCoordinateSystem e.g. {@link ImageAnalysis#COORDINATE_SYSTEM_ORIGINAL}
+     *                               the coordinates in MLKit output will be based on this value.
+     * @param executor               on which the consumer is invoked.
+     * @param consumer               invoked when there is new MLKit result.
      */
     @OptIn(markerClass = TransformExperimental.class)
     public MlKitAnalyzer(
@@ -214,7 +226,7 @@
      */
     @NonNull
     @Override
-    public final Size getTargetResolutionOverride() {
+    public final Size getDefaultTargetResolution() {
         Size size = DEFAULT_SIZE;
         for (Detector<?> detector : mDetectors) {
             Size detectorSize = getTargetResolution(detector.getDetectorType());
diff --git a/camera/camera-mlkit-vision/src/test/java/androidx/camera/mlkit/vision/MlKitAnalyzerTest.kt b/camera/camera-mlkit-vision/src/test/java/androidx/camera/mlkit/vision/MlKitAnalyzerTest.kt
index 96cee82..23cd954 100644
--- a/camera/camera-mlkit-vision/src/test/java/androidx/camera/mlkit/vision/MlKitAnalyzerTest.kt
+++ b/camera/camera-mlkit-vision/src/test/java/androidx/camera/mlkit/vision/MlKitAnalyzerTest.kt
@@ -63,7 +63,7 @@
             directExecutor()
         ) {}
 
-        assertThat(mlKitAnalyzer.targetResolutionOverride).isEqualTo(Size(1280, 720))
+        assertThat(mlKitAnalyzer.defaultTargetResolution).isEqualTo(Size(1280, 720))
     }
 
     @Test
diff --git a/camera/camera-testing/lint-baseline.xml b/camera/camera-testing/lint-baseline.xml
index 9c6bf5d..d2d3da4 100644
--- a/camera/camera-testing/lint-baseline.xml
+++ b/camera/camera-testing/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnsafeOptInUsageError"
@@ -7,9 +7,7 @@
         errorLine1="    public boolean isZslSupported() {"
         errorLine2="                   ~~~~~~~~~~~~~~">
         <location
-            file="src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java"
-            line="196"
-            column="20"/>
+            file="src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java"/>
     </issue>
 
     <issue
@@ -18,9 +16,7 @@
         errorLine1="        return false;"
         errorLine2="               ~~~~~">
         <location
-            file="src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java"
-            line="197"
-            column="16"/>
+            file="src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java"/>
     </issue>
 
     <issue
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 ab20fff..eb87f4f 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
@@ -25,10 +25,12 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
 import android.media.CamcorderProfile;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
@@ -37,6 +39,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.util.Log;
+import android.view.Surface;
 
 import androidx.annotation.DoNotInline;
 import androidx.annotation.GuardedBy;
@@ -55,6 +58,7 @@
 import androidx.camera.core.impl.utils.futures.Futures;
 import androidx.camera.core.internal.CameraUseCaseAdapter;
 import androidx.concurrent.futures.CallbackToFutureAdapter;
+import androidx.concurrent.futures.CallbackToFutureAdapter.Completer;
 import androidx.core.util.Preconditions;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -76,6 +80,7 @@
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -135,7 +140,6 @@
      * <p>After the camera is no longer needed {@link #releaseCameraDevice(CameraDeviceHolder)}
      * should be called to clean up resources.
      *
-     * @throws CameraAccessException if the device is unable to access the camera
      * @throws InterruptedException  if a {@link CameraDevice} can not be retrieved within a set
      *                               time
      */
@@ -144,7 +148,7 @@
     public static CameraDeviceHolder getCameraDevice(
             @NonNull String cameraId,
             @Nullable CameraDevice.StateCallback stateCallback)
-            throws CameraAccessException, InterruptedException, TimeoutException,
+            throws InterruptedException, TimeoutException,
             ExecutionException {
         return new CameraDeviceHolder(getCameraManager(), cameraId, stateCallback);
     }
@@ -192,7 +196,9 @@
         @GuardedBy("mLock")
         CameraDevice mCameraDevice;
         final HandlerThread mHandlerThread;
+        final Handler mHandler;
         private ListenableFuture<Void> mCloseFuture;
+        CameraCaptureSessionHolder mCameraCaptureSessionHolder;
 
         @RequiresPermission(Manifest.permission.CAMERA)
         CameraDeviceHolder(@NonNull CameraManager cameraManager, @NonNull String cameraId,
@@ -200,6 +206,7 @@
                 throws InterruptedException, ExecutionException, TimeoutException {
             mHandlerThread = new HandlerThread(String.format("CameraThread-%s", cameraId));
             mHandlerThread.start();
+            mHandler = new Handler(mHandlerThread.getLooper());
 
             ListenableFuture<Void> cameraOpenFuture = openCamera(cameraManager, cameraId,
                     stateCallback);
@@ -217,7 +224,7 @@
                 mCloseFuture = CallbackToFutureAdapter.getFuture(closeCompleter -> {
                     cameraManager.openCamera(cameraId,
                             new DeviceStateCallbackImpl(openCompleter, closeCompleter,
-                                    extraStateCallback), new Handler(mHandlerThread.getLooper()));
+                                    extraStateCallback), mHandler);
                     return "Close[cameraId=" + cameraId + "]";
                 });
                 return "Open[cameraId=" + cameraId + "]";
@@ -267,6 +274,7 @@
             public void onDisconnected(@NonNull CameraDevice cameraDevice) {
                 synchronized (mLock) {
                     mCameraDevice = null;
+                    mCameraCaptureSessionHolder = null;
                 }
                 if (mExtraStateCallback != null) {
                     mExtraStateCallback.onDisconnected(cameraDevice);
@@ -282,6 +290,7 @@
                         notifyOpenFailed = true;
                     } else {
                         mCameraDevice = null;
+                        mCameraCaptureSessionHolder = null;
                     }
                 }
                 if (mExtraStateCallback != null) {
@@ -305,6 +314,7 @@
             synchronized (mLock) {
                 cameraDevice = mCameraDevice;
                 mCameraDevice = null;
+                mCameraCaptureSessionHolder = null;
             }
 
             if (cameraDevice != null) {
@@ -315,6 +325,14 @@
         }
 
         /**
+         * Returns a ListenableFuture representing the closed state.
+         */
+        @NonNull
+        public ListenableFuture<Void> getClosedFuture() {
+            return Futures.nonCancellationPropagating(mCloseFuture);
+        }
+
+        /**
          * Returns the camera device if it opened successfully and has not been closed.
          */
         @Nullable
@@ -323,6 +341,179 @@
                 return mCameraDevice;
             }
         }
+
+        /**
+         * Create a {@link CameraCaptureSession} by the hold CameraDevice
+         *
+         * @param surfaces the surfaces used to create CameraCaptureSession
+         * @return the CameraCaptureSession holder
+         */
+        @NonNull
+        public CameraCaptureSessionHolder createCaptureSession(@NonNull List<Surface> surfaces)
+                throws ExecutionException, InterruptedException, TimeoutException {
+            synchronized (mLock) {
+                Preconditions.checkState(mCameraDevice != null, "Camera is closed.");
+            }
+            if (mCameraCaptureSessionHolder != null) {
+                mCameraCaptureSessionHolder.close();
+                mCameraCaptureSessionHolder = null;
+            }
+            mCameraCaptureSessionHolder = new CameraCaptureSessionHolder(this, surfaces, null);
+            return mCameraCaptureSessionHolder;
+        }
+    }
+
+    /**
+     * A container class used to hold a {@link CameraCaptureSession}.
+     *
+     * <p>This class contains a valid {@link CameraCaptureSession} that can be retrieved with
+     * {@link #get()}, unless the session has been closed.
+     *
+     * <p>The instance can be obtained via {@link CameraDeviceHolder#createCaptureSession}
+     * and will be closed by creating another CameraCaptureSessionHolder. The latest instance will
+     * be closed when the associated CameraDeviceHolder is released by
+     * {@link CameraUtil#releaseCameraDevice(CameraDeviceHolder)}.
+     */
+    @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info
+    public static class CameraCaptureSessionHolder {
+
+        private final CameraDeviceHolder mCameraDeviceHolder;
+        private CameraCaptureSession mCameraCaptureSession;
+        private ListenableFuture<Void> mCloseFuture;
+
+        CameraCaptureSessionHolder(@NonNull CameraDeviceHolder cameraDeviceHolder,
+                @NonNull List<Surface> surfaces,
+                @Nullable CameraCaptureSession.StateCallback stateCallback
+        ) throws ExecutionException, InterruptedException, TimeoutException {
+            mCameraDeviceHolder = cameraDeviceHolder;
+            CameraDevice cameraDevice = Preconditions.checkNotNull(cameraDeviceHolder.get());
+            ListenableFuture<CameraCaptureSession> openFuture = openCaptureSession(cameraDevice,
+                    surfaces, stateCallback, cameraDeviceHolder.mHandler);
+
+            mCameraCaptureSession = openFuture.get(5, TimeUnit.SECONDS);
+        }
+
+        @SuppressWarnings("deprecation")
+        @NonNull
+        private ListenableFuture<CameraCaptureSession> openCaptureSession(
+                @NonNull CameraDevice cameraDevice,
+                @NonNull List<Surface> surfaces,
+                @Nullable CameraCaptureSession.StateCallback stateCallback,
+                @NonNull Handler handler) {
+            return CallbackToFutureAdapter.getFuture(
+                    openCompleter -> {
+                        mCloseFuture = CallbackToFutureAdapter.getFuture(
+                                closeCompleter -> {
+                                    cameraDevice.createCaptureSession(surfaces,
+                                            new SessionStateCallbackImpl(
+                                                    openCompleter, closeCompleter, stateCallback),
+                                            handler);
+                                    return "Close CameraCaptureSession";
+                                });
+                        return "Open CameraCaptureSession";
+                    });
+        }
+
+        void close() throws ExecutionException, InterruptedException, TimeoutException {
+            if (mCameraCaptureSession != null) {
+                mCameraCaptureSession.close();
+                mCameraCaptureSession = null;
+            }
+            mCloseFuture.get(10L, TimeUnit.SECONDS);
+        }
+
+        /**
+         * A simplified method to start a repeating capture request.
+         *
+         * <p>For advance usage, use {@link #get} to obtain the CameraCaptureSession and then issue
+         * repeating request.
+         *
+         * @param template one of the {@link CameraDevice} template.
+         * @param surfaces the surfaces add to the repeating request
+         * @param captureParams the pairs of {@link CaptureRequest.Key} and value
+         * @param captureCallback the capture callback
+         * @throws CameraAccessException if fail to issue the request
+         */
+        @SuppressWarnings("unchecked") // Cast to CaptureRequest.Key<Object>
+        public void startRepeating(int template, @NonNull List<Surface> surfaces,
+                @Nullable Map<CaptureRequest.Key<?>, Object> captureParams,
+                @Nullable CameraCaptureSession.CaptureCallback captureCallback)
+                throws CameraAccessException {
+            checkSessionOrThrow();
+            CameraDevice cameraDevice = mCameraDeviceHolder.get();
+            Preconditions.checkState(cameraDevice != null, "CameraDevice is closed.");
+            CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(template);
+            for (Surface surface : surfaces) {
+                builder.addTarget(surface);
+            }
+            if (captureParams != null) {
+                for (Map.Entry<CaptureRequest.Key<?>, Object> entry : captureParams.entrySet()) {
+                    builder.set((CaptureRequest.Key<Object>) entry.getKey(), entry.getValue());
+                }
+            }
+            mCameraCaptureSession.setRepeatingRequest(builder.build(), captureCallback,
+                    mCameraDeviceHolder.mHandler);
+        }
+
+        /**
+         * Returns the camera capture session if it opened successfully and has not been closed.
+         *
+         * @throws IllegalStateException if the camera capture session is closed
+         */
+        @NonNull
+        public CameraCaptureSession get() {
+            checkSessionOrThrow();
+            return mCameraCaptureSession;
+        }
+
+        private void checkSessionOrThrow() {
+            Preconditions.checkState(mCameraCaptureSession != null,
+                    "CameraCaptureSession is closed");
+        }
+
+        @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info
+        private static class SessionStateCallbackImpl extends
+                CameraCaptureSession.StateCallback {
+            private final Completer<CameraCaptureSession> mOpenCompleter;
+            private final CallbackToFutureAdapter.Completer<Void> mCloseCompleter;
+            @Nullable
+            private final CameraCaptureSession.StateCallback mExtraStateCallback;
+
+            SessionStateCallbackImpl(
+                    @NonNull Completer<CameraCaptureSession> openCompleter,
+                    @NonNull Completer<Void> closeCompleter,
+                    @Nullable CameraCaptureSession.StateCallback extraStateCallback) {
+                mOpenCompleter = openCompleter;
+                mCloseCompleter = closeCompleter;
+                mExtraStateCallback = extraStateCallback;
+            }
+
+            @Override
+            public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
+                if (mExtraStateCallback != null) {
+                    mExtraStateCallback.onConfigured(cameraCaptureSession);
+                }
+                mOpenCompleter.set(cameraCaptureSession);
+            }
+
+            @Override
+            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
+                if (mExtraStateCallback != null) {
+                    mExtraStateCallback.onConfigureFailed(cameraCaptureSession);
+                }
+                mOpenCompleter.setException(new RuntimeException("Failed to "
+                        + "open CameraCaptureSession"));
+                mCloseCompleter.set(null);
+            }
+
+            @Override
+            public void onClosed(@NonNull CameraCaptureSession session) {
+                if (mExtraStateCallback != null) {
+                    mExtraStateCallback.onClosed(session);
+                }
+                mCloseCompleter.set(null);
+            }
+        }
     }
 
     /**
@@ -466,6 +657,9 @@
     public static boolean requiresCorrectedAspectRatio(@CameraSelector.LensFacing int lensFacing) {
         Integer hardwareLevelValue;
         CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(lensFacing);
+        if (cameraCharacteristics == null) {
+            return false;
+        }
         hardwareLevelValue = cameraCharacteristics.get(
                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
         // There is a bug because of a flipped scaling factor in the intermediate texture
@@ -490,7 +684,7 @@
         for (String cameraId : getBackwardCompatibleCameraIdListOrThrow()) {
             CameraCharacteristics characteristics = getCameraCharacteristicsOrThrow(cameraId);
             Integer cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
-            if (cameraLensFacing != null && cameraLensFacing.intValue() == lensFacingInteger) {
+            if (cameraLensFacing != null && cameraLensFacing == lensFacingInteger) {
                 return cameraId;
             }
         }
@@ -510,11 +704,11 @@
         for (String cameraId : getBackwardCompatibleCameraIdListOrThrow()) {
             CameraCharacteristics characteristics = getCameraCharacteristicsOrThrow(cameraId);
             Integer cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
-            if (cameraLensFacing == null || cameraLensFacing.intValue() != lensFacingInteger) {
+            if (cameraLensFacing == null || cameraLensFacing != lensFacingInteger) {
                 continue;
             }
             Boolean hasFlashUnit = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
-            if (hasFlashUnit != null && hasFlashUnit.booleanValue()) {
+            if (hasFlashUnit != null && hasFlashUnit) {
                 return true;
             }
         }
@@ -535,7 +729,7 @@
         for (String cameraId : getBackwardCompatibleCameraIdListOrThrow()) {
             CameraCharacteristics characteristics = getCameraCharacteristicsOrThrow(cameraId);
             Integer cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
-            if (cameraLensFacing != null && cameraLensFacing.intValue() == lensFacingInteger) {
+            if (cameraLensFacing != null && cameraLensFacing == lensFacingInteger) {
                 return characteristics;
             }
         }
@@ -586,7 +780,7 @@
         for (String cameraId : getBackwardCompatibleCameraIdListOrThrow()) {
             CameraCharacteristics characteristics = getCameraCharacteristicsOrThrow(cameraId);
             Integer cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
-            if (cameraLensFacing == null || cameraLensFacing.intValue() != lensFacingInteger) {
+            if (cameraLensFacing == null || cameraLensFacing != lensFacingInteger) {
                 continue;
             }
             return characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
@@ -667,7 +861,7 @@
      */
     @NonNull
     public static TestRule checkVideoRecordingResource() {
-        RuleChain rule = RuleChain.outerRule((base, description) -> new Statement() {
+        return RuleChain.outerRule((base, description) -> new Statement() {
             @RequiresApi(api = Build.VERSION_CODES.M)
             @Override
             public void evaluate() throws Throwable {
@@ -676,8 +870,6 @@
                 base.evaluate();
             }
         });
-
-        return rule;
     }
 
     /**
@@ -722,7 +914,9 @@
                 checkResult = false;
             } finally {
                 Logger.i(LOG_TAG, "codec.release()");
-                codec.release();
+                if (codec != null) {
+                    codec.release();
+                }
             }
         }
 
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/HandlerUtil.java b/camera/camera-testing/src/main/java/androidx/camera/testing/HandlerUtil.java
index 49c27af..694d9d9 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/HandlerUtil.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/HandlerUtil.java
@@ -20,6 +20,7 @@
 import android.os.Looper;
 import android.os.MessageQueue;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.camera.testing.compat.LooperCompat;
 
@@ -35,25 +36,19 @@
      * @throws RuntimeException if unable to obtain the {@link MessageQueue} for the {@link
      * Handler}.
      */
-    public static void waitForLooperToIdle(Handler handler) throws InterruptedException {
+    public static void waitForLooperToIdle(@NonNull Handler handler) throws InterruptedException {
         final Looper looper = handler.getLooper();
         final Semaphore semaphore = new Semaphore(0);
 
         // Post a message that will add the idle handler. This will ensure the handler is not
         // already idle before setting the idle handler, causing the idle handler to never be
         // called.
-        handler.post(new Runnable() {
-            @Override
-            public void run() {
-                MessageQueue messageQueue = LooperCompat.getQueue(looper);
-                messageQueue.addIdleHandler(new MessageQueue.IdleHandler() {
-                    @Override
-                    public boolean queueIdle() {
-                        semaphore.release();
-                        return false;
-                    }
-                });
-            }
+        handler.post(() -> {
+            MessageQueue messageQueue = LooperCompat.getQueue(looper);
+            messageQueue.addIdleHandler(() -> {
+                semaphore.release();
+                return false;
+            });
         });
 
         // Wait for idle
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/compat/LooperCompat.java b/camera/camera-testing/src/main/java/androidx/camera/testing/compat/LooperCompat.java
index cb9b679..3abbd17 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/compat/LooperCompat.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/compat/LooperCompat.java
@@ -31,16 +31,18 @@
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public final class LooperCompat {
     /** Returns the {@link MessageQueue} for the given {@link Looper}. */
-    public static MessageQueue getQueue(Looper looper) {
+    @NonNull
+    public static MessageQueue getQueue(@NonNull Looper looper) {
         if (Build.VERSION.SDK_INT >= 23) {
             return Api23Impl.getQueue(looper);
         } else {
             Method getQueue;
             try {
                 getQueue = Looper.class.getMethod("getQueue");
+                //noinspection ConstantConditions
                 return (MessageQueue) getQueue.invoke(looper);
 
-            } catch (NoSuchMethodException e) {
+            } catch (NoSuchMethodException | NullPointerException e) {
                 throw new RuntimeException("Unable to retrieve getQueue via reflection.");
             } catch (IllegalAccessException | InvocationTargetException e) {
                 throw new RuntimeException("Unable to invoke getQueue via reflection.");
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraCaptureResult.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraCaptureResult.java
index e0b97b1..d0029eb 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraCaptureResult.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraCaptureResult.java
@@ -41,23 +41,23 @@
     private long mTimestamp = -1L;
     private TagBundle mTag = TagBundle.emptyBundle();
 
-    public void setAfMode(CameraCaptureMetaData.AfMode mode) {
+    public void setAfMode(@NonNull CameraCaptureMetaData.AfMode mode) {
         mAfMode = mode;
     }
 
-    public void setAfState(CameraCaptureMetaData.AfState state) {
+    public void setAfState(@NonNull CameraCaptureMetaData.AfState state) {
         mAfState = state;
     }
 
-    public void setAeState(CameraCaptureMetaData.AeState state) {
+    public void setAeState(@NonNull CameraCaptureMetaData.AeState state) {
         mAeState = state;
     }
 
-    public void setAwbState(CameraCaptureMetaData.AwbState state) {
+    public void setAwbState(@NonNull CameraCaptureMetaData.AwbState state) {
         mAwbState = state;
     }
 
-    public void setFlashState(CameraCaptureMetaData.FlashState state) {
+    public void setFlashState(@NonNull CameraCaptureMetaData.FlashState state) {
         mFlashState = state;
     }
 
@@ -65,7 +65,7 @@
         mTimestamp = timestamp;
     }
 
-    public void setTag(TagBundle tag) {
+    public void setTag(@NonNull TagBundle tag) {
         mTag = tag;
     }
 
@@ -115,6 +115,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("unused")
     @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static class Builder {
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManager.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManager.java
index ab66eba1..0626fd8 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManager.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraDeviceSurfaceManager.java
@@ -35,14 +35,15 @@
 
     public static final Size MAX_OUTPUT_SIZE = new Size(4032, 3024); // 12.2 MP
 
-    private Map<String, Map<Class<? extends UseCaseConfig<?>>, Size>> mDefinedResolutions =
+    private final Map<String, Map<Class<? extends UseCaseConfig<?>>, Size>> mDefinedResolutions =
             new HashMap<>();
 
     /**
      * Sets the given suggested resolutions for the specified camera Id and use case type.
      */
-    public void setSuggestedResolution(String cameraId, Class<? extends UseCaseConfig<?>> type,
-            Size size) {
+    public void setSuggestedResolution(@NonNull String cameraId,
+            @NonNull Class<? extends UseCaseConfig<?>> type,
+            @NonNull Size size) {
         Map<Class<? extends UseCaseConfig<?>>, Size> useCaseConfigTypeToSizeMap =
                 mDefinedResolutions.get(cameraId);
         if (useCaseConfigTypeToSizeMap == null) {
@@ -54,12 +55,15 @@
     }
 
     @Override
-    public boolean checkSupported(String cameraId, List<SurfaceConfig> surfaceConfigList) {
+    public boolean checkSupported(@NonNull String cameraId,
+            @NonNull List<SurfaceConfig> surfaceConfigList) {
         return false;
     }
 
+    @NonNull
     @Override
-    public SurfaceConfig transformSurfaceConfig(String cameraId, int imageFormat, Size size) {
+    public SurfaceConfig transformSurfaceConfig(@NonNull String cameraId, int imageFormat,
+            @NonNull Size size) {
 
         //returns a placeholder SurfaceConfig
         return SurfaceConfig.create(SurfaceConfig.ConfigType.PRIV,
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java
index 27dfbd3..8d5d98d 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java
@@ -56,8 +56,7 @@
     private final int mSensorRotation;
     @CameraSelector.LensFacing
     private final int mLensFacing;
-    private final boolean mHasFlashUnit = true;
-    private MutableLiveData<Integer> mTorchState = new MutableLiveData<>(TorchState.OFF);
+    private final MutableLiveData<Integer> mTorchState = new MutableLiveData<>(TorchState.OFF);
     private final MutableLiveData<ZoomState> mZoomLiveData;
     private MutableLiveData<CameraState> mCameraStateLiveData;
     private String mImplementationType = IMPLEMENTATION_TYPE_FAKE;
@@ -92,6 +91,7 @@
         mZoomLiveData = new MutableLiveData<>(ImmutableZoomState.create(1.0f, 4.0f, 1.0f, 0.0f));
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
     @Nullable
     @Override
     public Integer getLensFacing() {
@@ -125,7 +125,7 @@
 
     @Override
     public boolean hasFlashUnit() {
-        return mHasFlashUnit;
+        return true;
     }
 
     @NonNull
@@ -202,6 +202,7 @@
     }
 
     /** Adds a quirk to the list of this camera's quirks. */
+    @SuppressWarnings("unused")
     public void addCameraQuirk(@NonNull final Quirk quirk) {
         mCameraQuirks.add(quirk);
     }
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCaptureStage.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCaptureStage.java
index 05aad09..75ab209 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCaptureStage.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCaptureStage.java
@@ -16,6 +16,8 @@
 
 package androidx.camera.testing.fakes;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
@@ -32,12 +34,24 @@
 public class FakeCaptureStage implements CaptureStage {
 
     private final int mId;
+
+    @NonNull
     private final CaptureConfig mCaptureConfig;
 
-    /** Create a FakeCaptureStage with the given parameters. */
-    public FakeCaptureStage(int id, CaptureConfig captureConfig) {
+    /**
+     * Create a FakeCaptureStage with the given parameters.
+     *
+     * If {@code captureConfig} is {@code null},
+     * {@link CaptureConfig#defaultEmptyCaptureConfig()} will be used as a default value.
+     */
+    public FakeCaptureStage(int id, @Nullable CaptureConfig captureConfig) {
         mId = id;
-        mCaptureConfig = captureConfig;
+
+        if (captureConfig == null) {
+            mCaptureConfig = CaptureConfig.defaultEmptyCaptureConfig();
+        } else {
+            mCaptureConfig = captureConfig;
+        }
     }
 
     @Override
@@ -45,6 +59,7 @@
         return mId;
     }
 
+    @NonNull
     @Override
     public CaptureConfig getCaptureConfig() {
         return mCaptureConfig;
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeImageProxy.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeImageProxy.java
index 2ed5aa2..ff8d209 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeImageProxy.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeImageProxy.java
@@ -40,7 +40,10 @@
     private int mFormat = 0;
     private int mHeight = 0;
     private int mWidth = 0;
+
+    @NonNull
     private PlaneProxy[] mPlaneProxy = new PlaneProxy[0];
+
     private boolean mClosed = false;
 
     @NonNull
@@ -162,7 +165,7 @@
         mWidth = width;
     }
 
-    public void setPlanes(PlaneProxy[] planeProxy) {
+    public void setPlanes(@NonNull PlaneProxy[] planeProxy) {
         mPlaneProxy = planeProxy;
     }
 
@@ -183,16 +186,12 @@
         synchronized (mReleaseLock) {
             if (mReleaseFuture == null) {
                 mReleaseFuture = CallbackToFutureAdapter.getFuture(
-                        new CallbackToFutureAdapter.Resolver<Void>() {
-                            @Override
-                            public Object attachCompleter(@NonNull
-                                    CallbackToFutureAdapter.Completer<Void> completer) {
-                                synchronized (mReleaseLock) {
-                                    Preconditions.checkState(mReleaseCompleter == null,
-                                            "Release completer expected to be null");
-                                    mReleaseCompleter = completer;
-                                    return "Release[imageProxy=" + FakeImageProxy.this + "]";
-                                }
+                        completer -> {
+                            synchronized (mReleaseLock) {
+                                Preconditions.checkState(mReleaseCompleter == null,
+                                        "Release completer expected to be null");
+                                mReleaseCompleter = completer;
+                                return "Release[imageProxy=" + FakeImageProxy.this + "]";
                             }
                         });
             }
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeImageReaderProxy.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeImageReaderProxy.java
index 29c6e3e..d999dba 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeImageReaderProxy.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeImageReaderProxy.java
@@ -47,6 +47,7 @@
     private int mImageFormat = ImageFormat.JPEG;
     private final int mMaxImages;
 
+    @Nullable
     private Surface mSurface;
 
     @Nullable
@@ -59,11 +60,11 @@
             BlockingQueue<ListenableFuture<Void>> mImageProxyBlockingQueue;
 
     // Queue of ImageProxys which have not yet been acquired.
-    private BlockingQueue<ImageProxy> mImageProxyAcquisitionQueue;
+    private final BlockingQueue<ImageProxy> mImageProxyAcquisitionQueue;
 
     // List of all ImageProxy which have been acquired. Close them all once the ImageReader is
     // closed
-    private List<ImageProxy> mOutboundImageProxy = new ArrayList<>();
+    private final List<ImageProxy> mOutboundImageProxy = new ArrayList<>();
 
     @SuppressWarnings("WeakerAccess") /* synthetic accessor */
     @Nullable
@@ -88,6 +89,7 @@
      *
      * @param maxImages The maximum number of images that can be acquired at once
      */
+    @SuppressWarnings("unused")
     @NonNull
     public static FakeImageReaderProxy newInstance(int width, int height, int format,
             int maxImages, long usage) {
@@ -192,7 +194,7 @@
         mExecutor = null;
     }
 
-    public void setSurface(Surface surface) {
+    public void setSurface(@Nullable Surface surface) {
         mSurface = surface;
     }
 
@@ -211,6 +213,7 @@
      * ImageProxy have been triggered without a {@link #acquireLatestImage()} or {@link
      * #acquireNextImage()} being called.
      */
+    @SuppressWarnings("ResultOfMethodCallIgnored")
     public void triggerImageAvailable(@NonNull TagBundle tagBundle,
             long timestamp) throws InterruptedException {
         FakeImageProxy fakeImageProxy = generateFakeImageProxy(tagBundle, timestamp);
diff --git a/camera/camera-testlib-extensions/lint-baseline.xml b/camera/camera-testlib-extensions/lint-baseline.xml
index 4b2b78c..5bd16c6 100644
--- a/camera/camera-testlib-extensions/lint-baseline.xml
+++ b/camera/camera-testlib-extensions/lint-baseline.xml
@@ -1,104 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
-        errorLine2="                     ~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public List&lt;CaptureStageImpl> getCaptureStages() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureProcessorImpl getCaptureProcessor() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,"
-        errorLine2="                       ~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,"
-        errorLine2="                                        ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Context context) {"
-        errorLine2="            ~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onPresetSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onEnableSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onDisableSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public List&lt;Pair&lt;Integer, Size[]&gt;> getSupportedResolutions() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java"/>
-    </issue>
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
@@ -214,105 +115,6 @@
         errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
         errorLine2="                     ~~~~~~">
         <location
-            file="src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public List&lt;CaptureStageImpl> getCaptureStages() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureProcessorImpl getCaptureProcessor() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,"
-        errorLine2="                       ~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,"
-        errorLine2="                                        ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Context context) {"
-        errorLine2="            ~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onPresetSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onEnableSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onDisableSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public List&lt;Pair&lt;Integer, Size[]&gt;> getSupportedResolutions() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
-        errorLine2="                     ~~~~~~">
-        <location
             file="src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java"/>
     </issue>
 
@@ -421,105 +223,6 @@
         errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
         errorLine2="                     ~~~~~~">
         <location
-            file="src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public List&lt;CaptureStageImpl> getCaptureStages() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureProcessorImpl getCaptureProcessor() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,"
-        errorLine2="                       ~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,"
-        errorLine2="                                        ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Context context) {"
-        errorLine2="            ~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onPresetSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onEnableSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onDisableSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public List&lt;Pair&lt;Integer, Size[]&gt;> getSupportedResolutions() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
-        errorLine2="                     ~~~~~~">
-        <location
             file="src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java"/>
     </issue>
 
@@ -625,33 +328,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void onOutputSurface(Surface surface, int imageFormat);"
-        errorLine2="                         ~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void process(Map&lt;Integer, Pair&lt;Image, TotalCaptureResult>> results);"
-        errorLine2="                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void onResolutionUpdate(Size size);"
-        errorLine2="                            ~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/CaptureProcessorImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    List&lt;Pair&lt;CaptureRequest.Key, Object>> getParameters();"
         errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -736,105 +412,6 @@
         errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
         errorLine2="                     ~~~~~~">
         <location
-            file="src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public List&lt;CaptureStageImpl> getCaptureStages() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureProcessorImpl getCaptureProcessor() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,"
-        errorLine2="                       ~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,"
-        errorLine2="                                        ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Context context) {"
-        errorLine2="            ~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onPresetSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onEnableSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onDisableSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public List&lt;Pair&lt;Integer, Size[]&gt;> getSupportedResolutions() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
-        errorLine2="                     ~~~~~~">
-        <location
             file="src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java"/>
     </issue>
 
@@ -940,159 +517,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    boolean isExtensionAvailable(String cameraId, CameraCharacteristics cameraCharacteristics);"
-        errorLine2="                                 ~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    boolean isExtensionAvailable(String cameraId, CameraCharacteristics cameraCharacteristics);"
-        errorLine2="                                                  ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void init(String cameraId, CameraCharacteristics cameraCharacteristics);"
-        errorLine2="              ~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void init(String cameraId, CameraCharacteristics cameraCharacteristics);"
-        errorLine2="                               ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    CaptureProcessorImpl getCaptureProcessor();"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    List&lt;CaptureStageImpl> getCaptureStages();"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
-        errorLine2="                     ~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public List&lt;CaptureStageImpl> getCaptureStages() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureProcessorImpl getCaptureProcessor() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,"
-        errorLine2="                       ~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,"
-        errorLine2="                                        ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Context context) {"
-        errorLine2="            ~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onPresetSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onEnableSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public CaptureStageImpl onDisableSession() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public List&lt;Pair&lt;Integer, Size[]&gt;> getSupportedResolutions() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {"
         errorLine2="                     ~~~~~~">
         <location
@@ -1264,24 +688,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void process(Image image, TotalCaptureResult result);"
-        errorLine2="                 ~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void process(Image image, TotalCaptureResult result);"
-        errorLine2="                              ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/camera/extensions/impl/PreviewImageProcessorImpl.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    void onOutputSurface(Surface surface, int imageFormat);"
         errorLine2="                         ~~~~~~~">
         <location
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
index ceef8d19..b33eb0f 100755
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoImageCaptureExtenderImpl.java
@@ -60,7 +60,8 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
     }
 
     @Override
@@ -98,8 +99,9 @@
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
 
     }
 
@@ -154,6 +156,7 @@
         return null;
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
     @Nullable
     @Override
     public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
@@ -166,7 +169,7 @@
         private ImageWriter mImageWriter;
 
         @Override
-        public void onOutputSurface(Surface surface, int imageFormat) {
+        public void onOutputSurface(@NonNull Surface surface, int imageFormat) {
             mImageWriter = ImageWriter.newInstance(surface, 1);
         }
 
@@ -200,7 +203,7 @@
         }
 
         @Override
-        public void onResolutionUpdate(Size size) {
+        public void onResolutionUpdate(@NonNull Size size) {
 
         }
 
@@ -216,11 +219,13 @@
         }
     }
 
+    @NonNull
     @Override
     public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
         return null;
     }
 
+    @NonNull
     @Override
     public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
         return null;
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
index e2aabfa..4c2e2a1 100755
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/AutoPreviewExtenderImpl.java
@@ -46,7 +46,8 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
     }
 
     @Override
@@ -61,6 +62,7 @@
         return CameraCharacteristicAvailability.isEffectAvailable(cameraCharacteristics, EFFECT);
     }
 
+    @NonNull
     @Override
     public CaptureStageImpl getCaptureStage() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
@@ -71,24 +73,28 @@
         return captureStage;
     }
 
+    @NonNull
     @Override
     public ProcessorType getProcessorType() {
         return ProcessorType.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY;
     }
 
+    @Nullable
     @Override
     public ProcessorImpl getProcessor() {
         return RequestUpdateProcessorImpls.noUpdateProcessor();
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         return null;
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
 
     }
 
@@ -97,6 +103,7 @@
 
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         // The CaptureRequest parameters will be set via SessionConfiguration#setSessionParameters
@@ -113,6 +120,8 @@
         return captureStage;
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
@@ -123,6 +132,8 @@
         return captureStage;
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
index 6d44ebe..39e2fb8 100755
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyImageCaptureExtenderImpl.java
@@ -64,7 +64,8 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         mCameraCharacteristics = cameraCharacteristics;
     }
 
@@ -103,8 +104,9 @@
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
 
     }
 
@@ -192,7 +194,7 @@
         private ImageWriter mImageWriter;
 
         @Override
-        public void onOutputSurface(Surface surface, int imageFormat) {
+        public void onOutputSurface(@NonNull Surface surface, int imageFormat) {
             mImageWriter = ImageWriter.newInstance(surface, 1);
         }
 
@@ -231,7 +233,7 @@
         }
 
         @Override
-        public void onResolutionUpdate(Size size) {
+        public void onResolutionUpdate(@NonNull Size size) {
 
         }
 
@@ -241,11 +243,13 @@
         }
     }
 
+    @NonNull
     @Override
     public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
         return null;
     }
 
+    @NonNull
     @Override
     public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
         return null;
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
index a49c0e6..ba8c013 100755
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BeautyPreviewExtenderImpl.java
@@ -51,7 +51,8 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         mCameraCharacteristics = cameraCharacteristics;
     }
 
@@ -67,6 +68,7 @@
         return CameraCharacteristicAvailability.isEffectAvailable(cameraCharacteristics, EFFECT);
     }
 
+    @NonNull
     @Override
     public CaptureStageImpl getCaptureStage() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
@@ -78,15 +80,19 @@
     }
 
     @Override
+    @NonNull
     public ProcessorType getProcessorType() {
         return ProcessorType.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY;
     }
 
+    @Nullable
     @Override
     public ProcessorImpl getProcessor() {
         return RequestUpdateProcessorImpls.noUpdateProcessor();
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         List<Pair<Integer, Size[]>> formatResolutionsPairList = new ArrayList<>();
@@ -108,8 +114,9 @@
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
 
     }
 
@@ -118,6 +125,7 @@
 
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         // The CaptureRequest parameters will be set via SessionConfiguration#setSessionParameters
@@ -134,6 +142,8 @@
         return captureStage;
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
@@ -144,6 +154,8 @@
         return captureStage;
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
index 5bfb538..0eedc2d 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehImageCaptureExtenderImpl.java
@@ -60,7 +60,8 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
     }
 
     @Override
@@ -98,8 +99,9 @@
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
 
     }
 
@@ -166,7 +168,7 @@
         private ImageWriter mImageWriter;
 
         @Override
-        public void onOutputSurface(Surface surface, int imageFormat) {
+        public void onOutputSurface(@NonNull Surface surface, int imageFormat) {
             mImageWriter = ImageWriter.newInstance(surface, 1);
         }
 
@@ -206,7 +208,7 @@
         }
 
         @Override
-        public void onResolutionUpdate(Size size) {
+        public void onResolutionUpdate(@NonNull Size size) {
 
         }
 
@@ -216,11 +218,13 @@
         }
     }
 
+    @NonNull
     @Override
     public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
         return null;
     }
 
+    @NonNull
     @Override
     public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
         return null;
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
index 7d72e9b..60d6246 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/BokehPreviewExtenderImpl.java
@@ -49,7 +49,8 @@
     public BokehPreviewExtenderImpl() {}
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
         mCaptureStage = new SettableCaptureStage(DEFAULT_STAGE_ID);
         mCaptureStage.addCaptureRequestParameters(CaptureRequest.CONTROL_EFFECT_MODE,
                 CaptureRequest.CONTROL_EFFECT_MODE_OFF);
@@ -67,18 +68,21 @@
         return CameraCharacteristicAvailability.isEffectAvailable(cameraCharacteristics, EFFECT);
     }
 
+    @NonNull
     @Override
     public CaptureStageImpl getCaptureStage() {
         return mCaptureStage;
     }
 
+    @NonNull
     @Override
     public ProcessorType getProcessorType() {
         return ProcessorType.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY;
     }
 
     // Switches effect every 90 frames
-    private RequestUpdateProcessorImpl mRequestUpdateProcessor = new RequestUpdateProcessorImpl() {
+    private final RequestUpdateProcessorImpl mRequestUpdateProcessor =
+            new RequestUpdateProcessorImpl() {
         private int mFrameCount = 0;
         private Integer mEffectMode = CaptureRequest.CONTROL_EFFECT_MODE_OFF;
 
@@ -105,29 +109,32 @@
         }
 
         @Override
-        public void onOutputSurface(Surface surface, int imageFormat) {}
+        public void onOutputSurface(@NonNull Surface surface, int imageFormat) {}
 
         @Override
-        public void onResolutionUpdate(Size size) {}
+        public void onResolutionUpdate(@NonNull Size size) {}
 
         @Override
         public void onImageFormatUpdate(int imageFormat) {}
     };
 
-
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
+    @Nullable
     @Override
     public ProcessorImpl getProcessor() {
         return mRequestUpdateProcessor;
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         return null;
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
 
     }
 
@@ -136,6 +143,7 @@
 
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         // The CaptureRequest parameters will be set via SessionConfiguration#setSessionParameters
@@ -152,6 +160,8 @@
         return captureStage;
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
@@ -162,6 +172,8 @@
         return captureStage;
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/CaptureStageImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/CaptureStageImpl.java
index 27adb97a..fc86020 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/CaptureStageImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/CaptureStageImpl.java
@@ -19,6 +19,7 @@
 import android.hardware.camera2.CaptureRequest;
 import android.util.Pair;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 
 import java.util.List;
@@ -37,5 +38,6 @@
      * Returns the set of {@link CaptureRequest.Key} and the corresponding values that will be
      * set for a single {@link CaptureRequest}.
      */
+    @NonNull
     List<Pair<CaptureRequest.Key, Object>> getParameters();
 }
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java
index 935673b..b13f602 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtenderStateListener.java
@@ -17,11 +17,14 @@
 package androidx.camera.extensions.impl;
 
 import android.content.Context;
+import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.params.SessionConfiguration;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 
 /**
@@ -37,12 +40,12 @@
      * where the use case is started and would be able to allocate resources here. After onInit() is
      * called, the camera ID, cameraCharacteristics and context will not change until onDeInit()
      * has been called.
-     *
      * @param cameraId The camera2 id string of the camera.
      * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
      * @param context The {@link Context} used for CameraX.
      */
-    void onInit(String cameraId, CameraCharacteristics cameraCharacteristics, Context context);
+    void onInit(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context);
 
     /**
      * Notify to de-initialize the extension. This callback will be invoked after unbind.
@@ -53,7 +56,7 @@
 
     /**
      * This will be invoked before creating a
-     * {@link android.hardware.camera2.CameraCaptureSession}. The {@link CaptureRequest}
+     * {@link CameraCaptureSession}. The {@link CaptureRequest}
      * parameters returned via {@link CaptureStageImpl} will be passed to the camera device as
      * part of the capture session initialization via
      * {@link SessionConfiguration#setSessionParameters(CaptureRequest)} which only supported
@@ -62,10 +65,11 @@
      *
      * @return The request information to set the session wide camera parameters.
      */
+    @Nullable
     CaptureStageImpl onPresetSession();
 
     /**
-     * This will be invoked once after the {@link android.hardware.camera2.CameraCaptureSession}
+     * This will be invoked once after the {@link CameraCaptureSession}
      * has been created. The {@link CaptureRequest} parameters returned via
      * {@link CaptureStageImpl} will be used to generate a single request to the current
      * configured {@link CameraDevice}. The generated request will be submitted to camera before
@@ -73,15 +77,17 @@
      *
      * @return The request information to create a single capture request to camera device.
      */
+    @Nullable
     CaptureStageImpl onEnableSession();
 
     /**
-     * This will be invoked before the {@link android.hardware.camera2.CameraCaptureSession} is
+     * This will be invoked before the {@link CameraCaptureSession} is
      * closed. The {@link CaptureRequest} parameters returned via {@link CaptureStageImpl} will
      * be used to generate a single request to the currently configured {@link CameraDevice}. The
      * generated request will be submitted to camera before the CameraCaptureSession is closed.
      *
      * @return The request information to customize the session.
      */
+    @Nullable
     CaptureStageImpl onDisableSession();
 }
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
index a438fdc..212bea0 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ExtensionVersionImpl.java
@@ -18,6 +18,7 @@
 
 import android.util.Log;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 
 /**
@@ -59,7 +60,9 @@
      * @return the version that vendor supported in this device. The MAJOR.MINOR.PATCH format
      * should be used.
      */
-    public String checkApiVersion(String version) {
+    @SuppressWarnings("unused")
+    @NonNull
+    public String checkApiVersion(@NonNull String version) {
         Log.d(TAG, "Extension device library version " + VERSION);
         return VERSION;
     }
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
index fe09802..a5cdf2a 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrImageCaptureExtenderImpl.java
@@ -67,7 +67,8 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
     }
 
     @Override
@@ -142,8 +143,9 @@
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
 
     }
 
@@ -197,7 +199,7 @@
         private ImageWriter mImageWriter;
 
         @Override
-        public void onOutputSurface(Surface surface, int imageFormat) {
+        public void onOutputSurface(@NonNull Surface surface, int imageFormat) {
             mImageWriter = ImageWriter.newInstance(surface, 1);
         }
 
@@ -303,7 +305,7 @@
         }
 
         @Override
-        public void onResolutionUpdate(Size size) {
+        public void onResolutionUpdate(@NonNull Size size) {
 
         }
 
@@ -313,11 +315,13 @@
         }
     }
 
+    @NonNull
     @Override
     public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
         return null;
     }
 
+    @NonNull
     @Override
     public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
         return null;
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
index 5af32e2..09c2ca37 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/HdrPreviewExtenderImpl.java
@@ -56,7 +56,8 @@
     public HdrPreviewExtenderImpl() { }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
     }
 
     @Override
@@ -66,6 +67,7 @@
         return true;
     }
 
+    @NonNull
     @Override
     public CaptureStageImpl getCaptureStage() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
@@ -73,16 +75,20 @@
         return new SettableCaptureStage(DEFAULT_STAGE_ID);
     }
 
+    @NonNull
     @Override
     public ProcessorType getProcessorType() {
         return ProcessorType.PROCESSOR_TYPE_IMAGE_PROCESSOR;
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
+    @Nullable
     @Override
     public ProcessorImpl getProcessor() {
         return mProcessor;
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         return null;
@@ -92,8 +98,9 @@
             new HdrPreviewExtenderPreviewImageProcessorImpl();
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
         mGlHandlerThread = new GlHandlerThread();
         mGlHandlerThread.postToRenderThread(() -> mRenderer = new GLImage2SurfaceRenderer());
     }
@@ -112,16 +119,19 @@
         }
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         return null;
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         return null;
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         return null;
@@ -144,7 +154,7 @@
         }
 
         @Override
-        public void onOutputSurface(Surface surface, int imageFormat) {
+        public void onOutputSurface(@NonNull Surface surface, int imageFormat) {
             mSurface = surface;
             setWindowSurface();
         }
@@ -167,7 +177,7 @@
         }
 
         @Override
-        public void onResolutionUpdate(Size size) {
+        public void onResolutionUpdate(@NonNull Size size) {
             mSize = size;
             setWindowSurface();
             if (mGlHandlerThread != null) {
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
index 6d0b4f4..6ed8f4d 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ImageCaptureExtenderImpl.java
@@ -16,15 +16,17 @@
 
 package androidx.camera.extensions.impl;
 
-import android.annotation.SuppressLint;
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
 import android.util.Pair;
 import android.util.Range;
 import android.util.Size;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 
 import java.util.List;
@@ -35,7 +37,6 @@
  * @since 1.0
  */
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
-@SuppressLint("UnknownNullness")
 public interface ImageCaptureExtenderImpl extends ExtenderStateListener {
     /**
      * Indicates whether the extension is supported on the device.
@@ -44,7 +45,8 @@
      * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
      * @return true if the extension is supported, otherwise false
      */
-    boolean isExtensionAvailable(String cameraId, CameraCharacteristics cameraCharacteristics);
+    boolean isExtensionAvailable(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics);
 
     /**
      * Initializes the extender to be used with the specified camera.
@@ -55,14 +57,16 @@
      * @param cameraId The camera2 id string of the camera.
      * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
      */
-    void init(String cameraId, CameraCharacteristics cameraCharacteristics);
+    void init(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics);
 
     /**
      * The processing that will be done on a set of captures to create and image with the effect.
      */
+    @Nullable
     CaptureProcessorImpl getCaptureProcessor();
 
     /** The set of captures that are needed to create an image with the effect. */
+    @Nullable
     List<CaptureStageImpl> getCaptureStages();
 
     /**
@@ -77,14 +81,15 @@
      * <p>Pair list composed with {@link ImageFormat} and {@link Size} array will be returned.
      *
      * <p>The returned resolutions should be subset of the supported sizes retrieved from
-     * {@link android.hardware.camera2.params.StreamConfigurationMap} for the camera device. If the
+     * {@link StreamConfigurationMap} for the camera device. If the
      * returned list is not null, it will be used to find the best resolutions combination for
      * the bound use cases.
      *
      * @return the customized supported resolutions, or null to support all sizes retrieved from
-     *         {@link android.hardware.camera2.params.StreamConfigurationMap}.
+     * {@link StreamConfigurationMap}.
      * @since 1.1
      */
+    @Nullable
     List<Pair<Integer, Size[]>> getSupportedResolutions();
 
     /**
@@ -101,7 +106,8 @@
      * null if no capture latency info can be provided.
      * @since 1.2
      */
-    Range<Long> getEstimatedCaptureLatencyRange(Size captureOutputSize);
+    @Nullable
+    Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize);
 
     /**
      * Return a list of orthogonal capture request keys.
@@ -142,6 +148,7 @@
      * are not supported.
      * @since 1.3
      */
+    @NonNull
     List<CaptureRequest.Key> getAvailableCaptureRequestKeys();
 
     /**
@@ -161,5 +168,6 @@
      * supported.
      * @since 1.3
      */
+    @NonNull
     List<CaptureResult.Key> getAvailableCaptureResultKeys();
 }
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
index c106921..4febfb4 100755
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightImageCaptureExtenderImpl.java
@@ -60,7 +60,8 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
     }
 
     @Override
@@ -98,8 +99,9 @@
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
 
     }
 
@@ -154,6 +156,7 @@
         return null;
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
     @Nullable
     @Override
     public Range<Long> getEstimatedCaptureLatencyRange(@Nullable Size captureOutputSize) {
@@ -166,7 +169,7 @@
         private ImageWriter mImageWriter;
 
         @Override
-        public void onOutputSurface(Surface surface, int imageFormat) {
+        public void onOutputSurface(@NonNull Surface surface, int imageFormat) {
             mImageWriter = ImageWriter.newInstance(surface, 1);
         }
 
@@ -205,7 +208,7 @@
         }
 
         @Override
-        public void onResolutionUpdate(Size size) {
+        public void onResolutionUpdate(@NonNull Size size) {
         }
 
         @Override
@@ -213,11 +216,13 @@
         }
     }
 
+    @NonNull
     @Override
     public List<CaptureRequest.Key> getAvailableCaptureRequestKeys() {
         return null;
     }
 
+    @NonNull
     @Override
     public List<CaptureResult.Key> getAvailableCaptureResultKeys() {
         return null;
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
index 2df3724..f9b95c0 100755
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/NightPreviewExtenderImpl.java
@@ -46,7 +46,8 @@
     }
 
     @Override
-    public void init(String cameraId, CameraCharacteristics cameraCharacteristics) {
+    public void init(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics) {
     }
 
     @Override
@@ -61,6 +62,7 @@
         return CameraCharacteristicAvailability.isEffectAvailable(cameraCharacteristics, EFFECT);
     }
 
+    @NonNull
     @Override
     public CaptureStageImpl getCaptureStage() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
@@ -71,24 +73,28 @@
         return captureStage;
     }
 
+    @NonNull
     @Override
     public ProcessorType getProcessorType() {
         return ProcessorType.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY;
     }
 
+    @Nullable
     @Override
     public ProcessorImpl getProcessor() {
         return RequestUpdateProcessorImpls.noUpdateProcessor();
     }
 
+    @Nullable
     @Override
     public List<Pair<Integer, Size[]>> getSupportedResolutions() {
         return null;
     }
 
     @Override
-    public void onInit(String cameraId, CameraCharacteristics cameraCharacteristics,
-            Context context) {
+    public void onInit(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics,
+            @NonNull Context context) {
 
     }
 
@@ -97,6 +103,7 @@
 
     }
 
+    @Nullable
     @Override
     public CaptureStageImpl onPresetSession() {
         // The CaptureRequest parameters will be set via SessionConfiguration#setSessionParameters
@@ -113,6 +120,8 @@
         return captureStage;
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
+    @Nullable
     @Override
     public CaptureStageImpl onEnableSession() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
@@ -123,6 +132,8 @@
         return captureStage;
     }
 
+    @SuppressWarnings("ConstantConditions") // Super method is nullable.
+    @Nullable
     @Override
     public CaptureStageImpl onDisableSession() {
         // Set the necessary CaptureRequest parameters via CaptureStage, here we use some
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
index 4613f24..93cbcb9 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/PreviewExtenderImpl.java
@@ -18,10 +18,12 @@
 
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.TotalCaptureResult;
 import android.util.Pair;
 import android.util.Size;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 
@@ -51,33 +53,35 @@
      * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
      * @return true if the extension is supported, otherwise false
      */
-    boolean isExtensionAvailable(String cameraId, CameraCharacteristics cameraCharacteristics);
+    boolean isExtensionAvailable(@NonNull String cameraId,
+            @NonNull CameraCharacteristics cameraCharacteristics);
 
     /**
      * Initializes the extender to be used with the specified camera.
      *
      * <p>This should be called before any other method on the extender. The exception is {@link
      * #isExtensionAvailable(String, CameraCharacteristics)}.
-     *
-     * @param cameraId The camera2 id string of the camera.
+     *  @param cameraId The camera2 id string of the camera.
      * @param cameraCharacteristics The {@link CameraCharacteristics} of the camera.
      */
-    void init(String cameraId, CameraCharacteristics cameraCharacteristics);
+    void init(@NonNull String cameraId, @NonNull CameraCharacteristics cameraCharacteristics);
 
     /**
      * The set of parameters required to produce the effect on the preview stream.
      *
      * <p> This will be the initial set of parameters used for the preview
-     * {@link android.hardware.camera2.CaptureRequest}. If the {@link ProcessorType} is defined as
+     * {@link CaptureRequest}. If the {@link ProcessorType} is defined as
      * {@link ProcessorType#PROCESSOR_TYPE_REQUEST_UPDATE_ONLY} then this will be updated when
      * the {@link RequestUpdateProcessorImpl#process(TotalCaptureResult)} from {@link
      * #getProcessor()} has been called, this should be updated to reflect the new {@link
      * CaptureStageImpl}. If the processing step returns a {@code null}, meaning the required
      * parameters has not changed, then calling this will return the previous non-null value.
      */
+    @NonNull
     CaptureStageImpl getCaptureStage();
 
     /** The type of preview processing to use. */
+    @NonNull
     ProcessorType getProcessorType();
 
     /**
@@ -93,6 +97,7 @@
      * <tr><td> PROCESSOR_TYPE_NONE </td> <td> null </td> </tr>
      * </table>
      */
+    @Nullable
     ProcessorImpl getProcessor();
 
     /**
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ProcessorImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ProcessorImpl.java
index 663a16a..a339cca5 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ProcessorImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/ProcessorImpl.java
@@ -19,6 +19,7 @@
 import android.util.Size;
 import android.view.Surface;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 
 /**
@@ -26,6 +27,7 @@
  *
  * @since 1.0
  */
+@SuppressWarnings("unused")
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
 public interface ProcessorImpl {
     /**
@@ -34,23 +36,23 @@
      * @param surface     The {@link Surface} that the ProcessorImpl should write data into.
      * @param imageFormat The format of that the surface expects.
      */
-    void onOutputSurface(Surface surface, int imageFormat);
+    void onOutputSurface(@NonNull Surface surface, int imageFormat);
 
     /**
      * Invoked when CameraX changes the configured output resolution.
      *
-     * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
-     * input to be at the specified resolution.
+     * <p>After this call, {@link CaptureProcessorImpl} should expect any
+     * {@link android.media.Image} received as input to be at the specified resolution.
      *
      * @param size for the surface.
      */
-    void onResolutionUpdate(Size size);
+    void onResolutionUpdate(@NonNull Size size);
 
     /**
      * Invoked when CameraX changes the configured input image format.
      *
-     * <p>After this call, {@link CaptureProcessorImpl} should expect any {@link Image} received as
-     * input to have the specified image format.
+     * <p>After this call, {@link CaptureProcessorImpl} should expect any
+     * {@link android.media.Image} received as input to have the specified image format.
      *
      * @param imageFormat for the surface.
      */
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
index d42aa2a..8a6a2e2 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpl.java
@@ -18,6 +18,7 @@
 
 import android.hardware.camera2.TotalCaptureResult;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 
 /**
@@ -35,5 +36,6 @@
      * @return The updated parameters used for the repeating requests. If this is {@code null} then
      * the previous parameters will be used.
      */
-    CaptureStageImpl process(TotalCaptureResult result);
+    @Nullable
+    CaptureStageImpl process(@Nullable TotalCaptureResult result);
 }
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpls.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpls.java
index 45ac4ab..09356c9 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpls.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/RequestUpdateProcessorImpls.java
@@ -20,6 +20,7 @@
 import android.util.Size;
 import android.view.Surface;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 
 @RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
@@ -32,10 +33,10 @@
                 }
 
                 @Override
-                public void onOutputSurface(Surface surface, int imageFormat) {}
+                public void onOutputSurface(@NonNull Surface surface, int imageFormat) {}
 
                 @Override
-                public void onResolutionUpdate(Size size) {}
+                public void onResolutionUpdate(@NonNull Size size) {}
 
                 @Override
                 public void onImageFormatUpdate(int imageFormat) {}
diff --git a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/SettableCaptureStage.java b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/SettableCaptureStage.java
index 8aecf5d..05a7f76 100644
--- a/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/SettableCaptureStage.java
+++ b/camera/camera-testlib-extensions/src/main/java/androidx/camera/extensions/impl/SettableCaptureStage.java
@@ -19,6 +19,7 @@
 import android.hardware.camera2.CaptureRequest;
 import android.util.Pair;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 
 import java.util.ArrayList;
@@ -51,6 +52,7 @@
         return mId;
     }
 
+    @NonNull
     @Override
     public List<Pair<CaptureRequest.Key, Object>> getParameters() {
         List<Pair<CaptureRequest.Key, Object>> parameters = new ArrayList<>();
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/AudioChecker.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/AudioChecker.kt
new file mode 100644
index 0000000..dbd3371
--- /dev/null
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/AudioChecker.kt
@@ -0,0 +1,97 @@
+/*
+ * 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.camera.video
+
+import android.content.Context
+import androidx.annotation.RequiresApi
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.Logger
+import androidx.camera.core.impl.utils.executor.CameraXExecutors
+import androidx.camera.testing.CameraUtil
+import androidx.camera.video.internal.AudioSource
+import androidx.camera.video.internal.FakeBufferProvider
+import androidx.camera.video.internal.config.AudioSourceSettingsCamcorderProfileResolver
+import androidx.camera.video.internal.encoder.FakeInputBuffer
+import androidx.concurrent.futures.await
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.runBlocking
+
+@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
+class AudioChecker {
+
+    companion object {
+        private const val TAG = "AudioChecker"
+
+        fun canAudioSourceBeStarted(
+            context: Context,
+            cameraSelector: CameraSelector,
+            qualitySelector: QualitySelector
+        ): Boolean {
+            return try {
+                checkAudioSourceCanBeStarted(context, cameraSelector, qualitySelector)
+                Logger.i(TAG, "Audio source can be started.")
+                true
+            } catch (t: Throwable) {
+                Logger.i(TAG, "Audio source failed to start.", t)
+                false
+            }
+        }
+
+        private fun checkAudioSourceCanBeStarted(
+            context: Context,
+            cameraSelector: CameraSelector,
+            qualitySelector: QualitySelector
+        ) = runBlocking {
+            // Get audio source settings from CamcorderProfile
+            val cameraInfo =
+                CameraUtil.createCameraUseCaseAdapter(context, cameraSelector).cameraInfo
+            val videoCapabilities = VideoCapabilities.from(cameraInfo)
+            val quality = qualitySelector.getPrioritizedQualities(cameraInfo).first()
+            // Get a config using the default audio spec.
+            val audioSourceSettings =
+                AudioSourceSettingsCamcorderProfileResolver(
+                    AudioSpec.builder().build(),
+                    videoCapabilities.getProfile(quality)!!
+                ).get()
+            val audioSource = AudioSource(audioSourceSettings, CameraXExecutors.ioExecutor(), null)
+            try {
+                val completable = CompletableDeferred<Any?>()
+                audioSource.setAudioSourceCallback(CameraXExecutors.directExecutor(),
+                    object : AudioSource.AudioSourceCallback {
+                        override fun onSilenced(silenced: Boolean) {
+                            // Ignore
+                        }
+
+                        override fun onError(t: Throwable) {
+                            completable.completeExceptionally(t)
+                        }
+                    })
+
+                val fakeBufferProvider = FakeBufferProvider {
+                    completable.complete(null)
+                    FakeInputBuffer()
+                }
+                audioSource.setBufferProvider(fakeBufferProvider)
+                fakeBufferProvider.setActive(true)
+                audioSource.start()
+                completable.await()
+            } finally {
+                audioSource.release().await()
+            }
+        }
+    }
+}
\ No newline at end of file
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 84c6554..a75dd4a 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
@@ -40,6 +40,7 @@
 import androidx.camera.testing.CameraUtil
 import androidx.camera.testing.SurfaceTextureProvider
 import androidx.camera.testing.fakes.FakeLifecycleOwner
+import androidx.camera.video.VideoRecordEvent.Finalize.ERROR_NONE
 import androidx.camera.video.VideoRecordEvent.Finalize.ERROR_SOURCE_INACTIVE
 import androidx.core.util.Consumer
 import androidx.test.core.app.ApplicationProvider
@@ -53,7 +54,8 @@
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
 import org.junit.After
-import org.junit.Assume
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -87,6 +89,7 @@
     companion object {
         private const val VIDEO_TIMEOUT_SEC = 10L
         private const val TAG = "VideoRecordingTest"
+
         @JvmStatic
         @Parameterized.Parameters
         fun data(): Collection<Array<Any>> {
@@ -110,6 +113,12 @@
 
     private lateinit var finalize: VideoRecordEvent.Finalize
 
+    private val audioSourceAvailable by lazy {
+        AudioChecker.canAudioSourceBeStarted(
+            context, cameraSelector, Recorder.DEFAULT_QUALITY_SELECTOR
+        )
+    }
+
     private val videoRecordEventListener = Consumer<VideoRecordEvent> {
         when (it) {
             is VideoRecordEvent.Start -> {
@@ -137,9 +146,9 @@
 
     @Before
     fun setUp() {
-        Assume.assumeTrue(CameraUtil.hasCameraWithLensFacing(cameraSelector.lensFacing!!))
+        assumeTrue(CameraUtil.hasCameraWithLensFacing(cameraSelector.lensFacing!!))
         // Skip for b/168175357, b/233661493
-        Assume.assumeFalse(
+        assumeFalse(
             "Skip tests for Cuttlefish MediaCodec issues",
             Build.MODEL.contains("Cuttlefish") &&
                 (Build.VERSION.SDK_INT == 29 || Build.VERSION.SDK_INT == 33)
@@ -202,7 +211,7 @@
     @Test
     fun getCorrectResolution_when_setSupportedQuality() {
         // Pre-arrange.
-        Assume.assumeTrue(QualitySelector.getSupportedQualities(cameraInfo).isNotEmpty())
+        assumeTrue(QualitySelector.getSupportedQualities(cameraInfo).isNotEmpty())
         val qualityList = QualitySelector.getSupportedQualities(cameraInfo)
         Log.d(TAG, "CameraSelector: ${cameraSelector.lensFacing}, QualityList: $qualityList ")
 
@@ -315,6 +324,7 @@
         // Arrange.
         val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
         val file = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
+
         @Suppress("UNCHECKED_CAST")
         val mockListener = mock(Consumer::class.java) as Consumer<VideoRecordEvent>
         instrumentation.runOnMainSync {
@@ -346,7 +356,7 @@
         // Pre-check and arrange
         val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
         val analysis = ImageAnalysis.Builder().build()
-        Assume.assumeTrue(camera.isUseCasesCombinationSupported(preview, videoCapture, analysis))
+        assumeTrue(camera.isUseCasesCombinationSupported(preview, videoCapture, analysis))
 
         val file = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
         latchForVideoSaved = CountDownLatch(1)
@@ -382,7 +392,7 @@
         // Pre-check and arrange
         val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
         val imageCapture = ImageCapture.Builder().build()
-        Assume.assumeTrue(
+        assumeTrue(
             camera.isUseCasesCombinationSupported(
                 preview,
                 videoCapture,
@@ -423,67 +433,22 @@
 
     @Test
     fun canRecordMultipleFilesInARow() {
-        @Suppress("UNCHECKED_CAST")
-        val mockListener = mock(Consumer::class.java) as Consumer<VideoRecordEvent>
         val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
         instrumentation.runOnMainSync {
             cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, videoCapture)
         }
         val file1 = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
-
-        val inOrder = inOrder(mockListener)
-        videoCapture.output.prepareRecording(context, FileOutputOptions.Builder(file1).build())
-            .withAudioEnabled()
-            .start(CameraXExecutors.directExecutor(), mockListener).use { activeRecording ->
-
-                inOrder.verify(mockListener, timeout(5000L))
-                    .accept(any(VideoRecordEvent.Start::class.java))
-                inOrder.verify(mockListener, timeout(15000L).atLeast(5))
-                    .accept(any(VideoRecordEvent.Status::class.java))
-
-                activeRecording.stop()
-            }
-
-        inOrder.verify(mockListener, timeout(5000L))
-            .accept(any(VideoRecordEvent.Finalize::class.java))
+        performRecording(videoCapture, file1, includeAudio = audioSourceAvailable)
 
         val file2 = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
-
-        videoCapture.output.prepareRecording(context, FileOutputOptions.Builder(file2).build())
-            .withAudioEnabled()
-            .start(CameraXExecutors.directExecutor(), mockListener).use { activeRecording ->
-
-                inOrder.verify(mockListener, timeout(5000L))
-                    .accept(any(VideoRecordEvent.Start::class.java))
-                inOrder.verify(mockListener, timeout(15000L).atLeast(5))
-                    .accept(any(VideoRecordEvent.Status::class.java))
-
-                activeRecording.stop()
-            }
-
-        inOrder.verify(mockListener, timeout(5000L))
-            .accept(any(VideoRecordEvent.Finalize::class.java))
+        performRecording(videoCapture, file2, includeAudio = audioSourceAvailable)
 
         val file3 = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
+        performRecording(videoCapture, file3, includeAudio = audioSourceAvailable)
 
-        videoCapture.output.prepareRecording(context, FileOutputOptions.Builder(file3).build())
-            .withAudioEnabled()
-            .start(CameraXExecutors.directExecutor(), mockListener).use { activeRecording ->
-
-                inOrder.verify(mockListener, timeout(5000L))
-                    .accept(any(VideoRecordEvent.Start::class.java))
-                inOrder.verify(mockListener, timeout(15000L).atLeast(5))
-                    .accept(any(VideoRecordEvent.Status::class.java))
-
-                activeRecording.stop()
-            }
-
-        inOrder.verify(mockListener, timeout(5000L))
-            .accept(any(VideoRecordEvent.Finalize::class.java))
-
-        verifyRecordingResult(file1, true)
-        verifyRecordingResult(file2, true)
-        verifyRecordingResult(file3, true)
+        verifyRecordingResult(file1, audioSourceAvailable)
+        verifyRecordingResult(file2, audioSourceAvailable)
+        verifyRecordingResult(file3, audioSourceAvailable)
 
         file1.delete()
         file2.delete()
@@ -491,40 +456,70 @@
     }
 
     @Test
+    fun canRecordMultipleFilesWithThenWithoutAudio() {
+        // This test requires that audio is available
+        assumeTrue(audioSourceAvailable)
+        val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+        instrumentation.runOnMainSync {
+            cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, videoCapture)
+        }
+        val file1 = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
+        performRecording(videoCapture, file1, includeAudio = true)
+
+        val file2 = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
+        performRecording(videoCapture, file2, includeAudio = false)
+
+        verifyRecordingResult(file1, true)
+        verifyRecordingResult(file2, false)
+
+        file1.delete()
+        file2.delete()
+    }
+
+    @Test
+    fun canRecordMultipleFilesWithoutThenWithAudio() {
+        // This test requires that audio is available
+        assumeTrue(audioSourceAvailable)
+        val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+        instrumentation.runOnMainSync {
+            cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, videoCapture)
+        }
+        val file1 = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
+        performRecording(videoCapture, file1, includeAudio = false)
+
+        val file2 = File.createTempFile("CameraX", ".tmp").apply { deleteOnExit() }
+        performRecording(videoCapture, file2, includeAudio = true)
+
+        verifyRecordingResult(file1, false)
+        verifyRecordingResult(file2, true)
+
+        file1.delete()
+        file2.delete()
+    }
+
+    @Test
     fun canStartNextRecordingPausedAfterFirstRecordingFinalized() {
-        @Suppress("UNCHECKED_CAST")
-        val mockListener = mock(Consumer::class.java) as Consumer<VideoRecordEvent>
         val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
         instrumentation.runOnMainSync {
             cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, videoCapture)
         }
 
-        val file1 = File.createTempFile("CameraX1", ".tmp").apply { deleteOnExit() }
-        val file2 = File.createTempFile("CameraX2", ".tmp").apply { deleteOnExit() }
-
         // Start and stop a recording to ensure recorder is idling
-        val inOrder = inOrder(mockListener)
+        val file1 = File.createTempFile("CameraX1", ".tmp").apply { deleteOnExit() }
 
-        videoCapture.output.prepareRecording(context, FileOutputOptions.Builder(file1).build())
-            .withAudioEnabled()
-            .start(CameraXExecutors.directExecutor(), mockListener).use { activeRecording1 ->
-
-                inOrder.verify(mockListener, timeout(5000L))
-                    .accept(any(VideoRecordEvent.Start::class.java))
-
-                inOrder.verify(mockListener, timeout(15000L).atLeast(5))
-                    .accept(any(VideoRecordEvent.Status::class.java))
-
-                activeRecording1.stop()
-            }
-
-        inOrder.verify(mockListener, timeout(5000L))
-            .accept(any(VideoRecordEvent.Finalize::class.java))
+        performRecording(videoCapture, file1, audioSourceAvailable)
 
         // First recording is now finalized. Try starting second recording paused.
+        @Suppress("UNCHECKED_CAST")
+        val mockListener = mock(Consumer::class.java) as Consumer<VideoRecordEvent>
+        val inOrder = inOrder(mockListener)
+        val file2 = File.createTempFile("CameraX2", ".tmp").apply { deleteOnExit() }
         videoCapture.output.prepareRecording(context, FileOutputOptions.Builder(file2).build())
-            .withAudioEnabled()
-            .start(CameraXExecutors.directExecutor(), mockListener).use { activeRecording2 ->
+            .apply {
+                if (audioSourceAvailable) {
+                    withAudioEnabled()
+                }
+            }.start(CameraXExecutors.directExecutor(), mockListener).use { activeRecording2 ->
 
                 activeRecording2.pause()
 
@@ -585,6 +580,7 @@
 
     @Test
     fun canSwitchAudioOnOff() {
+        assumeTrue("Audio source is not available", audioSourceAvailable)
         @Suppress("UNCHECKED_CAST")
         val mockListener = mock(Consumer::class.java) as Consumer<VideoRecordEvent>
         val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
@@ -653,23 +649,78 @@
         }
     }
 
-    private fun startVideoRecording(videoCapture: VideoCapture<Recorder>, file: File):
-        Recording {
-            val recording = videoCapture.output
-                .prepareRecording(context, FileOutputOptions.Builder(file).build())
-                .start(CameraXExecutors.directExecutor(), videoRecordEventListener)
+    private fun performRecording(
+        videoCapture: VideoCapture<Recorder>,
+        file: File,
+        includeAudio: Boolean = false
+    ) {
+        @Suppress("UNCHECKED_CAST")
+        val mockListener = mock(Consumer::class.java) as Consumer<VideoRecordEvent>
+        val inOrder = inOrder(mockListener)
+        videoCapture.output.prepareRecording(context, FileOutputOptions.Builder(file).build())
+            .apply {
+                if (includeAudio) {
+                    withAudioEnabled()
+                }
+            }
+            .start(CameraXExecutors.directExecutor(), mockListener).use { activeRecording ->
 
-            try {
-                // Wait for status event to proceed recording for a while.
-                assertThat(latchForVideoRecording.await(VIDEO_TIMEOUT_SEC, TimeUnit.SECONDS))
-                    .isTrue()
-            } catch (ex: Exception) {
-                recording.stop()
-                throw ex
+                inOrder.verify(mockListener, timeout(5000L))
+                    .accept(any(VideoRecordEvent.Start::class.java))
+                inOrder.verify(mockListener, timeout(15000L).atLeast(5))
+                    .accept(any(VideoRecordEvent.Status::class.java))
+
+                activeRecording.stop()
             }
 
-            return recording
+        inOrder.verify(mockListener, timeout(5000L))
+            .accept(any(VideoRecordEvent.Finalize::class.java))
+
+        val captor = ArgumentCaptor.forClass(VideoRecordEvent::class.java)
+        verify(mockListener, atLeastOnce()).accept(captor.capture())
+
+        val finalizeEvent = captor.allValues.last() as VideoRecordEvent.Finalize
+
+        assertRecordingSuccessful(finalizeEvent, checkAudio = includeAudio)
+    }
+
+    private fun assertRecordingSuccessful(
+        finalizeEvent: VideoRecordEvent.Finalize,
+        checkAudio: Boolean = false
+    ) {
+        assertWithMessage(
+            "Recording did not finish successfully. Finished with error: ${
+                VideoRecordEvent.Finalize.errorToString(
+                    finalizeEvent.error
+                )
+            }"
+        ).that(finalizeEvent.error).isEqualTo(ERROR_NONE)
+        if (checkAudio) {
+            val audioStats = finalizeEvent.recordingStats.audioStats
+            assertWithMessage(
+                "Recording with audio encountered audio error." +
+                    "\n${audioStats.errorCause?.stackTraceToString()}"
+            ).that(audioStats.audioState).isNotEqualTo(AudioStats.AUDIO_STATE_ENCODER_ERROR)
         }
+    }
+
+    private fun startVideoRecording(videoCapture: VideoCapture<Recorder>, file: File):
+        Recording {
+        val recording = videoCapture.output
+            .prepareRecording(context, FileOutputOptions.Builder(file).build())
+            .start(CameraXExecutors.directExecutor(), videoRecordEventListener)
+
+        try {
+            // Wait for status event to proceed recording for a while.
+            assertThat(latchForVideoRecording.await(VIDEO_TIMEOUT_SEC, TimeUnit.SECONDS))
+                .isTrue()
+        } catch (ex: Exception) {
+            recording.stop()
+            throw ex
+        }
+
+        return recording
+    }
 
     private fun completeVideoRecording(videoCapture: VideoCapture<Recorder>, file: File) {
         val recording = startVideoRecording(videoCapture, file)
@@ -761,6 +812,7 @@
                 ) {
                     // No-op
                 }
+
                 override fun onSafeToRelease(surfaceTexture: SurfaceTexture) {
                     surfaceTexture.release()
                 }
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java b/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java
index 29cb814..da60534 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/Recorder.java
@@ -283,6 +283,8 @@
     private static final int AUDIO_CACHE_SIZE = 60;
     @VisibleForTesting
     static final EncoderFactory DEFAULT_ENCODER_FACTORY = EncoderImpl::new;
+    private static final Executor AUDIO_EXECUTOR =
+            CameraXExecutors.newSequentialExecutor(CameraXExecutors.ioExecutor());
 
     private final MutableStateObservable<StreamInfo> mStreamInfo;
     // Used only by getExecutor()
@@ -1261,7 +1263,11 @@
         AudioSource.Settings audioSourceSettings =
                 resolveAudioSourceSettings(audioMimeInfo, mediaSpec.getAudioSpec());
         try {
+            if (mAudioSource != null) {
+                releaseCurrentAudioSource();
+            }
             mAudioSource = setupAudioSource(recordingToStart, audioSourceSettings);
+            Logger.d(TAG, String.format("Set up new audio source: 0x%x", mAudioSource.hashCode()));
         } catch (AudioSourceAccessException e) {
             throw new ResourceCreationException(e);
         }
@@ -1290,35 +1296,34 @@
             throws AudioSourceAccessException {
 
         AudioSource audioSource = recordingToStart.performOneTimeAudioSourceCreation(
-                audioSourceSettings, CameraXExecutors.ioExecutor());
-
-        audioSource.setAudioSourceCallback(mSequentialExecutor,
-                new AudioSource.AudioSourceCallback() {
-                    @Override
-                    public void onSilenced(boolean silenced) {
-                        if (mIsAudioSourceSilenced != silenced) {
-                            mIsAudioSourceSilenced = silenced;
-                            mAudioErrorCause = silenced ? new IllegalStateException(
-                                    "The audio source has been silenced.") : null;
-                            updateInProgressStatusEvent();
-                        } else {
-                            Logger.w(TAG, "Audio source silenced transitions to the same state "
-                                    + silenced);
-                        }
-                    }
-
-                    @Override
-                    public void onError(@NonNull Throwable throwable) {
-                        if (throwable instanceof AudioSourceAccessException) {
-                            setAudioState(AudioState.DISABLED);
-                            updateInProgressStatusEvent();
-                        }
-                    }
-                });
+                audioSourceSettings, AUDIO_EXECUTOR);
 
         return audioSource;
     }
 
+    private void releaseCurrentAudioSource() {
+        if (mAudioSource == null) {
+            throw new AssertionError("Cannot release null audio source.");
+        }
+        AudioSource audioSource = mAudioSource;
+        mAudioSource = null;
+        Logger.d(TAG, String.format("Releasing audio source: 0x%x", audioSource.hashCode()));
+        // Run callback on direct executor since it is only logging
+        Futures.addCallback(audioSource.release(), new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(@Nullable Void result) {
+                Logger.d(TAG, String.format("Released audio source successfully: 0x%x",
+                        audioSource.hashCode()));
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                Logger.d(TAG, String.format("An error occurred while attempting to "
+                        + "release audio source: 0x%x", audioSource.hashCode()));
+            }
+        }, CameraXExecutors.directExecutor());
+    }
+
     @ExecutedBy("mSequentialExecutor")
     private void setupVideo(@NonNull SurfaceRequest surfaceRequest) {
         MediaSpec mediaSpec = getObservableData(mMediaSpec);
@@ -1611,7 +1616,7 @@
                 break;
         }
 
-        initEncoderCallbacks(recordingToStart);
+        initEncoderAndAudioSourceCallbacks(recordingToStart);
         if (isAudioEnabled()) {
             mAudioSource.start();
             mAudioEncoder.start();
@@ -1624,7 +1629,7 @@
     }
 
     @ExecutedBy("mSequentialExecutor")
-    private void initEncoderCallbacks(@NonNull RecordingRecord recordingToStart) {
+    private void initEncoderAndAudioSourceCallbacks(@NonNull RecordingRecord recordingToStart) {
         mEncodingFutures.add(CallbackToFutureAdapter.getFuture(
                 completer -> {
                     mVideoEncoder.setEncoderCallback(new EncoderCallback() {
@@ -1723,6 +1728,43 @@
         if (isAudioEnabled()) {
             mEncodingFutures.add(CallbackToFutureAdapter.getFuture(
                     completer -> {
+                        Consumer<Throwable> audioErrorConsumer = throwable -> {
+                            if (mAudioErrorCause == null) {
+                                // If the audio source or encoder encounters error, update the
+                                // status event to notify users. Then continue recording without
+                                // audio data.
+                                setAudioState(AudioState.ERROR);
+                                mAudioErrorCause = throwable;
+                                updateInProgressStatusEvent();
+                                completer.set(null);
+                            }
+                        };
+
+                        mAudioSource.setAudioSourceCallback(mSequentialExecutor,
+                                new AudioSource.AudioSourceCallback() {
+                                    @Override
+                                    public void onSilenced(boolean silenced) {
+                                        if (mIsAudioSourceSilenced != silenced) {
+                                            mIsAudioSourceSilenced = silenced;
+                                            mAudioErrorCause = silenced ? new IllegalStateException(
+                                                    "The audio source has been silenced.") : null;
+                                            updateInProgressStatusEvent();
+                                        } else {
+                                            Logger.w(TAG, "Audio source silenced transitions"
+                                                    + " to the same state " + silenced);
+                                        }
+                                    }
+
+                                    @Override
+                                    public void onError(@NonNull Throwable throwable) {
+                                        Logger.e(TAG, "Error occurred after audio source started.",
+                                                throwable);
+                                        if (throwable instanceof AudioSourceAccessException) {
+                                            audioErrorConsumer.accept(throwable);
+                                        }
+                                    }
+                                });
+
                         mAudioEncoder.setEncoderCallback(new EncoderCallback() {
                             @ExecutedBy("mSequentialExecutor")
                             @Override
@@ -1739,12 +1781,9 @@
                             @ExecutedBy("mSequentialExecutor")
                             @Override
                             public void onEncodeError(@NonNull EncodeException e) {
-                                // If the audio encoder encounters error, update the status event
-                                // to notify users. Then continue recording without audio data.
-                                setAudioState(AudioState.ERROR);
-                                mAudioErrorCause = e;
-                                updateInProgressStatusEvent();
-                                completer.set(null);
+                                if (mAudioErrorCause == null) {
+                                    audioErrorConsumer.accept(e);
+                                }
                             }
 
                             @ExecutedBy("mSequentialExecutor")
@@ -2005,9 +2044,7 @@
             mVideoOutputConfig = null;
         }
         if (mAudioSource != null) {
-            Logger.d(TAG, "Releasing audio source.");
-            mAudioSource.release();
-            mAudioSource = null;
+            releaseCurrentAudioSource();
         }
 
         setAudioState(AudioState.INITIALIZING);
@@ -2122,6 +2159,7 @@
                 // Fall-through
             case ACTIVE:
                 setAudioState(AudioState.IDLING);
+                mAudioSource.stop();
                 break;
             case ERROR:
                 // Reset audio state to INITIALIZING if the audio encoder encountered error, so
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/AudioSource.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/AudioSource.java
index 987aa380..f7129d4 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/AudioSource.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/AudioSource.java
@@ -46,9 +46,11 @@
 import androidx.camera.video.internal.compat.Api29Impl;
 import androidx.camera.video.internal.compat.Api31Impl;
 import androidx.camera.video.internal.encoder.InputBuffer;
+import androidx.concurrent.futures.CallbackToFutureAdapter;
 import androidx.core.util.Preconditions;
 
 import com.google.auto.value.AutoValue;
+import com.google.common.util.concurrent.ListenableFuture;
 
 import java.nio.ByteBuffer;
 import java.util.Arrays;
@@ -252,7 +254,7 @@
                     }
                     break;
                 case RELEASED:
-                    throw new IllegalStateException("AudioRecorder is released");
+                    throw new AssertionError("AudioRecorder is released");
             }
         });
     }
@@ -266,8 +268,6 @@
      *
      * <p>Audio data will start being sent to the {@link BufferProvider} when
      * {@link BufferProvider}'s state is {@link BufferProvider.State#ACTIVE}.
-     *
-     * @throws IllegalStateException if the AudioSource is released.
      */
     public void start() {
         mExecutor.execute(() -> {
@@ -280,7 +280,7 @@
                     // Do nothing
                     break;
                 case RELEASED:
-                    throw new IllegalStateException("AudioRecorder is released");
+                    throw new AssertionError("AudioRecorder is released");
             }
         });
     }
@@ -289,8 +289,6 @@
      * Stops the AudioSource.
      *
      * <p>Audio data will stop being sent to the {@link BufferProvider}.
-     *
-     * @throws IllegalStateException if it is released.
      */
     public void stop() {
         mExecutor.execute(() -> {
@@ -303,7 +301,8 @@
                     // Do nothing
                     break;
                 case RELEASED:
-                    throw new IllegalStateException("AudioRecorder is released");
+                    Logger.w(TAG, "AudioRecorder is released. "
+                            + "Calling stop() is a no-op.");
             }
         });
     }
@@ -313,25 +312,35 @@
      *
      * <p>Once the AudioSource is released, it can not be used any more.
      */
-    public void release() {
-        mExecutor.execute(() -> {
-            switch (mState) {
-                case STARTED:
-                    // Fall-through
-                case CONFIGURED:
-                    resetBufferProvider(null);
-                    if (Build.VERSION.SDK_INT >= 29) {
-                        Api29Impl.unregisterAudioRecordingCallback(mAudioRecord,
-                                mAudioRecordingCallback);
+    @NonNull
+    public ListenableFuture<Void> release() {
+        return CallbackToFutureAdapter.getFuture(completer -> {
+            mExecutor.execute(() -> {
+                try {
+                    switch (mState) {
+                        case STARTED:
+                            // Fall-through
+                        case CONFIGURED:
+                            resetBufferProvider(null);
+                            if (Build.VERSION.SDK_INT >= 29) {
+                                Api29Impl.unregisterAudioRecordingCallback(mAudioRecord,
+                                        mAudioRecordingCallback);
+                            }
+                            mAudioRecord.release();
+                            stopSendingAudio();
+                            setState(RELEASED);
+                            break;
+                        case RELEASED:
+                            // Do nothing
+                            break;
                     }
-                    mAudioRecord.release();
-                    stopSendingAudio();
-                    setState(RELEASED);
-                    break;
-                case RELEASED:
-                    // Do nothing
-                    break;
-            }
+                    completer.set(null);
+                } catch (Throwable t) {
+                    completer.setException(t);
+                }
+            });
+
+            return "AudioSource-release";
         });
     }
 
@@ -354,7 +363,7 @@
                 case STARTED:
                     // Fall-through
                 case RELEASED:
-                    throw new IllegalStateException("The audio recording callback must be "
+                    throw new AssertionError("The audio recording callback must be "
                             + "registered before the audio source is started.");
             }
         });
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
index a2fceec..b21f7bf 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
@@ -847,7 +847,7 @@
      * <p>Setting an analyzer function replaces any previous analyzer. Only one analyzer can be
      * set at any time.
      *
-     * <p> If the {@link ImageAnalysis.Analyzer#getTargetResolutionOverride()} returns a non-null
+     * <p> If the {@link ImageAnalysis.Analyzer#getDefaultTargetResolution()} returns a non-null
      * value, calling this method will reconfigure the camera which might cause additional
      * latency. To avoid this, set the value before controller is bound to the lifecycle.
      *
@@ -875,7 +875,7 @@
      *
      * <p>This will stop data from streaming to the {@link ImageAnalysis}.
      *
-     * <p> If the current {@link ImageAnalysis.Analyzer#getTargetResolutionOverride()} returns
+     * <p> If the current {@link ImageAnalysis.Analyzer#getDefaultTargetResolution()} returns
      * non-null value, calling this method will reconfigure the camera which might cause additional
      * latency. To avoid this, call this method when the lifecycle is not active.
      *
@@ -895,9 +895,9 @@
             @Nullable ImageAnalysis.Analyzer oldAnalyzer,
             @Nullable ImageAnalysis.Analyzer newAnalyzer) {
         Size oldResolution = oldAnalyzer == null ? null :
-                oldAnalyzer.getTargetResolutionOverride();
+                oldAnalyzer.getDefaultTargetResolution();
         Size newResolution = newAnalyzer == null ? null :
-                newAnalyzer.getTargetResolutionOverride();
+                newAnalyzer.getDefaultTargetResolution();
         if (!Objects.equals(oldResolution, newResolution)) {
             // Rebind ImageAnalysis to reconfigure target resolution.
             unbindImageAnalysisAndRecreate(mImageAnalysis.getBackpressureStrategy(),
@@ -1089,7 +1089,6 @@
         }
         if (outputTransform == null) {
             mAnalysisAnalyzer.updateTransform(null);
-
         } else if (mAnalysisAnalyzer.getTargetCoordinateSystem()
                 == COORDINATE_SYSTEM_VIEW_REFERENCED) {
             mAnalysisAnalyzer.updateTransform(outputTransform.getMatrix());
diff --git a/camera/camera-view/src/test/java/androidx/camera/view/CameraControllerTest.kt b/camera/camera-view/src/test/java/androidx/camera/view/CameraControllerTest.kt
index fd9935f..d69c153 100644
--- a/camera/camera-view/src/test/java/androidx/camera/view/CameraControllerTest.kt
+++ b/camera/camera-view/src/test/java/androidx/camera/view/CameraControllerTest.kt
@@ -127,7 +127,7 @@
                 // no-op
             }
 
-            override fun getTargetResolutionOverride(): Size? {
+            override fun getDefaultTargetResolution(): Size? {
                 return size
             }
         }
diff --git a/camera/camera-viewfinder/lint-baseline.xml b/camera/camera-viewfinder/lint-baseline.xml
index dad122f..a6c7750 100644
--- a/camera/camera-viewfinder/lint-baseline.xml
+++ b/camera/camera-viewfinder/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/BindUnbindUseCasesStressTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/BindUnbindUseCasesStressTest.kt
new file mode 100644
index 0000000..cfbc570
--- /dev/null
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/BindUnbindUseCasesStressTest.kt
@@ -0,0 +1,616 @@
+/*
+ * 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.camera.integration.core
+
+import android.content.Context
+import android.graphics.SurfaceTexture
+import android.os.Handler
+import android.os.HandlerThread
+import android.util.Log
+import android.util.Size
+import androidx.camera.camera2.Camera2Config
+import androidx.camera.core.Camera
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.ImageAnalysis
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageProxy
+import androidx.camera.core.Preview
+import androidx.camera.core.UseCase
+import androidx.camera.core.impl.utils.executor.CameraXExecutors
+import androidx.camera.integration.core.util.StressTestUtil.STRESS_TEST_OPERATION_REPEAT_COUNT
+import androidx.camera.integration.core.util.StressTestUtil.STRESS_TEST_REPEAT_COUNT
+import androidx.camera.integration.core.util.StressTestUtil.createCameraSelectorById
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.GLUtil
+import androidx.camera.testing.LabTestRule
+import androidx.camera.testing.SurfaceTextureProvider
+import androidx.camera.testing.fakes.FakeLifecycleOwner
+import androidx.camera.video.FileOutputOptions
+import androidx.camera.video.Recorder
+import androidx.camera.video.Recording
+import androidx.camera.video.VideoCapture
+import androidx.camera.video.VideoRecordEvent
+import androidx.core.util.Consumer
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.testutils.RepeatRule
+import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+import org.junit.After
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+private const val VIDEO_TIMEOUT_SEC = 10L
+private const val TAG = "BindUnbindUseCasesStressTest"
+private const val INVALID_TEX_ID = -1
+private var texId = INVALID_TEX_ID
+
+@LargeTest
+@RunWith(Parameterized::class)
+@SdkSuppress(minSdkVersion = 21)
+class BindUnbindUseCasesStressTest(
+    private val cameraId: String
+) {
+    @get:Rule
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
+
+    @get:Rule
+    val labTest: LabTestRule = LabTestRule()
+
+    @get:Rule
+    val repeatRule = RepeatRule()
+
+    private val context = ApplicationProvider.getApplicationContext<Context>()
+
+    private lateinit var cameraProvider: ProcessCameraProvider
+    private lateinit var camera: Camera
+    private lateinit var cameraIdCameraSelector: CameraSelector
+    private lateinit var preview: Preview
+    private lateinit var imageCapture: ImageCapture
+    private lateinit var lifecycleOwner: FakeLifecycleOwner
+
+    private lateinit var latchForVideoSaved: CountDownLatch
+    private lateinit var latchForVideoRecording: CountDownLatch
+
+    private lateinit var finalize: VideoRecordEvent.Finalize
+
+    private val videoRecordEventListener = Consumer<VideoRecordEvent> {
+        when (it) {
+            is VideoRecordEvent.Start -> {
+                // Recording start.
+                Log.d(TAG, "Recording start")
+            }
+            is VideoRecordEvent.Finalize -> {
+                // Recording stop.
+                Log.d(TAG, "Recording finalize")
+                finalize = it
+                latchForVideoSaved.countDown()
+            }
+            is VideoRecordEvent.Status -> {
+                // Make sure the recording proceed for a while.
+                latchForVideoRecording.countDown()
+            }
+            is VideoRecordEvent.Pause, is VideoRecordEvent.Resume -> {
+                // no op for this test, skip these event now.
+            }
+            else -> {
+                throw IllegalStateException()
+            }
+        }
+    }
+
+    @Before
+    fun setUp(): Unit = runBlocking {
+        cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
+
+        cameraIdCameraSelector = createCameraSelectorById(cameraId)
+
+        camera = withContext(Dispatchers.Main) {
+            lifecycleOwner = FakeLifecycleOwner()
+            lifecycleOwner.startAndResume()
+            cameraProvider.bindToLifecycle(lifecycleOwner, cameraIdCameraSelector)
+        }
+
+        preview = Preview.Builder().build()
+        imageCapture = ImageCapture.Builder().build()
+    }
+
+    @After
+    fun cleanUp(): Unit = runBlocking {
+        if (::cameraProvider.isInitialized) {
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+                cameraProvider.shutdown()[10000, TimeUnit.MILLISECONDS]
+            }
+        }
+    }
+
+    companion object {
+        @JvmStatic
+        @get:Parameterized.Parameters(name = "cameraId = {0}")
+        val parameters: Collection<String>
+            get() = CameraUtil.getBackwardCompatibleCameraIdListOrThrow()
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun bindUnbindUseCasesTenTimes_canCaptureImageInEachTime_withPreviewImageCapture(): Unit =
+        runBlocking {
+            bindUseCases_checkOutput_thenUnbindAll_repeatedly(preview, imageCapture)
+        }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun bindUnbindUseCasesTenTimes_canCaptureImageInEachTime_withPreviewImageCaptureImageAnalysis():
+        Unit = runBlocking {
+        val imageAnalysis = ImageAnalysis.Builder().build()
+        bindUseCases_checkOutput_thenUnbindAll_repeatedly(
+            preview,
+            imageCapture,
+            imageAnalysis = imageAnalysis
+        )
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun bindUnbindUseCasesTenTimes_canCaptureImageInEachTime_withPreviewVideoCapture(): Unit =
+        runBlocking {
+            val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+            bindUseCases_checkOutput_thenUnbindAll_repeatedly(preview, videoCapture = videoCapture)
+        }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun bindUnbindUseCasesTenTimes_canCaptureImageInEachTime_withPreviewVideoCaptureImageCapture():
+        Unit = runBlocking {
+        val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+        assumeTrue(camera.isUseCasesCombinationSupported(preview, imageCapture, videoCapture))
+        bindUseCases_checkOutput_thenUnbindAll_repeatedly(preview, imageCapture, videoCapture)
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun bindUnbindUseCasesTenTimes_canCaptureImageInEachTime_withPreviewVideoCaptureImageAnalysis():
+        Unit = runBlocking {
+        val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+        val imageAnalysis = ImageAnalysis.Builder().build()
+        assumeTrue(camera.isUseCasesCombinationSupported(preview, videoCapture, imageAnalysis))
+        bindUseCases_checkOutput_thenUnbindAll_repeatedly(
+            preview,
+            videoCapture = videoCapture,
+            imageAnalysis = imageAnalysis
+        )
+    }
+
+    /**
+     * Repeatedly binds use cases, checks the input use cases' capture functions can work well, and
+     * unbind all use cases.
+     *
+     * <p>This function checks the nullabilities of the input ImageCapture, VideoCapture and
+     * ImageAnalysis to determine whether the use cases will be bound together to run the test.
+     */
+    private fun bindUseCases_checkOutput_thenUnbindAll_repeatedly(
+        preview: Preview,
+        imageCapture: ImageCapture? = null,
+        videoCapture: VideoCapture<Recorder>? = null,
+        imageAnalysis: ImageAnalysis? = null,
+        repeatCount: Int = STRESS_TEST_OPERATION_REPEAT_COUNT
+    ): Unit = runBlocking {
+        for (i in 1..repeatCount) {
+            // Arrange.
+            // Sets up Preview frame available monitor
+            val previewFrameAvailableMonitor = PreviewFrameAvailableMonitor()
+
+            // Sets up the necessary objects for VideoCapture part if videCapture is non-null
+            var newVideoCapture: VideoCapture<Recorder>? = null
+            videoCapture?.let {
+                // VideoCapture needs to be recreated everytime until b/212654991 is fixed
+                newVideoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+            }
+
+            // Act: binds use cases
+            withContext(Dispatchers.Main) {
+                preview.setSurfaceProvider(
+                    SurfaceTextureProvider.createSurfaceTextureProvider(
+                        previewFrameAvailableMonitor.createSurfaceTextureCallback()
+                    )
+                )
+
+                val useCases = mutableListOf<UseCase>(preview)
+                imageCapture?.let { useCases.add(it) }
+                newVideoCapture?.let { useCases.add(it) }
+                imageAnalysis?.let { useCases.add(it) }
+
+                cameraProvider.bindToLifecycle(
+                    lifecycleOwner,
+                    cameraIdCameraSelector,
+                    *listOfNotNull(
+                        preview,
+                        imageCapture,
+                        newVideoCapture,
+                        imageAnalysis
+                    ).toTypedArray()
+                )
+            }
+
+            // Assert: checks that Preview frames can be received
+            previewFrameAvailableMonitor.awaitSurfaceTextureReadyAndAssert()
+            previewFrameAvailableMonitor.awaitAvailableFramesAndAssert()
+
+            // Assert: checks that the captured image of ImageCapture can be received
+            imageCapture?.let {
+                val imageCaptureCaptureSuccessMonitor = ImageCaptureCaptureSuccessMonitor()
+
+                it.takePicture(
+                    Executors.newSingleThreadExecutor(),
+                    imageCaptureCaptureSuccessMonitor.createCaptureCallback()
+                )
+
+                imageCaptureCaptureSuccessMonitor.awaitCaptureSuccessAndAssert()
+            }
+
+            // Assert: checks that a video can be recorded by VideoCapture
+            newVideoCapture?.let {
+                latchForVideoSaved = CountDownLatch(1)
+                latchForVideoRecording = CountDownLatch(5)
+                val videoFile = File.createTempFile("camerax-video", ".tmp").apply {
+                    deleteOnExit()
+                }
+
+                completeVideoRecording(it, videoFile)
+                videoFile.delete()
+            }
+
+            // Assert: checks that images can be received by the ImageAnalysis.Analyzer
+            imageAnalysis?.let {
+                val analyzerFrameAvailableMonitor = ImageAnalysisImageAvailableMonitor()
+                it.setAnalyzer(
+                    Executors.newSingleThreadExecutor(),
+                    analyzerFrameAvailableMonitor.createAnalyzer()
+                )
+                analyzerFrameAvailableMonitor.awaitAvailableFramesAndAssert()
+            }
+
+            // Clean it up.
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+            }
+        }
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun canCaptureImage_afterBindUnbindUseCasesTenTimes_withPreviewImageCapture(): Unit =
+        runBlocking {
+            bindUseCases_unbindAll_repeatedly_thenCheckOutput(preview, imageCapture)
+        }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun canCaptureImage_afterBindUnbindUseCasesTenTimes_withPreviewImageCaptureImageAnalysis():
+        Unit = runBlocking {
+        val imageAnalysis = ImageAnalysis.Builder().build()
+        assumeTrue(camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis))
+        bindUseCases_unbindAll_repeatedly_thenCheckOutput(
+            preview,
+            imageCapture,
+            imageAnalysis = imageAnalysis
+        )
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun canCaptureImage_afterBindUnbindUseCasesTenTimes_withPreviewVideoCapture(): Unit =
+        runBlocking {
+            val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+            bindUseCases_unbindAll_repeatedly_thenCheckOutput(preview, videoCapture = videoCapture)
+        }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun canCaptureImage_afterBindUnbindUseCasesTenTimes_withPreviewVideoCaptureImageCapture():
+        Unit = runBlocking {
+        val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+        assumeTrue(camera.isUseCasesCombinationSupported(preview, imageCapture, videoCapture))
+        bindUseCases_unbindAll_repeatedly_thenCheckOutput(preview, imageCapture, videoCapture)
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun canCaptureImage_afterBindUnbindUseCasesTenTimes_withPreviewVideoCaptureImageAnalysis():
+        Unit = runBlocking {
+        val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+        val imageAnalysis = ImageAnalysis.Builder().build()
+        assumeTrue(camera.isUseCasesCombinationSupported(preview, videoCapture, imageAnalysis))
+        bindUseCases_unbindAll_repeatedly_thenCheckOutput(
+            preview,
+            videoCapture = videoCapture,
+            imageAnalysis = imageAnalysis
+        )
+    }
+
+    /**
+     * Repeatedly binds use cases and unbind all, then checks the input use cases' capture
+     * functions can work well.
+     *
+     * <p>This function checks the nullabilities of the input ImageCapture, VideoCapture and
+     * ImageAnalysis to determine whether the use cases will be bound together to run the test.
+     */
+    private fun bindUseCases_unbindAll_repeatedly_thenCheckOutput(
+        preview: Preview,
+        imageCapture: ImageCapture? = null,
+        videoCapture: VideoCapture<Recorder>? = null,
+        imageAnalysis: ImageAnalysis? = null,
+        repeatCount: Int = STRESS_TEST_OPERATION_REPEAT_COUNT
+    ): Unit = runBlocking {
+        lateinit var previewFrameAvailableMonitor: PreviewFrameAvailableMonitor
+        var newVideoCapture: VideoCapture<Recorder>? = null
+
+        for (i in 1..repeatCount) {
+            // Arrange.
+            // Sets up Preview frame available monitor
+            previewFrameAvailableMonitor = PreviewFrameAvailableMonitor()
+
+            // Sets up the necessary objects for VideoCapture part if videCapture is non-null
+            videoCapture?.let {
+                // VideoCapture needs to be recreated everytime until b/212654991 is fixed
+                newVideoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+            }
+
+            // Act: binds use cases
+            withContext(Dispatchers.Main) {
+                preview.setSurfaceProvider(
+                    SurfaceTextureProvider.createSurfaceTextureProvider(
+                        previewFrameAvailableMonitor.createSurfaceTextureCallback()
+                    )
+                )
+
+                val useCases = mutableListOf<UseCase>(preview)
+                imageCapture?.let { useCases.add(it) }
+                newVideoCapture?.let { useCases.add(it) }
+                imageAnalysis?.let { useCases.add(it) }
+
+                cameraProvider.bindToLifecycle(
+                    lifecycleOwner,
+                    cameraIdCameraSelector,
+                    *listOfNotNull(
+                        preview,
+                        imageCapture,
+                        newVideoCapture,
+                        imageAnalysis
+                    ).toTypedArray()
+                )
+
+                // Clean it up: do not unbind at the last time
+                if (i != repeatCount) {
+                    cameraProvider.unbindAll()
+                }
+            }
+        }
+
+        // Assert: checks that Preview frames can be received
+        previewFrameAvailableMonitor.awaitSurfaceTextureReadyAndAssert()
+        previewFrameAvailableMonitor.awaitAvailableFramesAndAssert()
+
+        // Assert: checks that the captured image of ImageCapture can be received
+        imageCapture?.let {
+            val imageCaptureCaptureSuccessMonitor = ImageCaptureCaptureSuccessMonitor()
+
+            it.takePicture(
+                Executors.newSingleThreadExecutor(),
+                imageCaptureCaptureSuccessMonitor.createCaptureCallback()
+            )
+
+            imageCaptureCaptureSuccessMonitor.awaitCaptureSuccessAndAssert()
+        }
+
+        // Assert: checks that a video can be recorded by VideoCapture
+        newVideoCapture?.let {
+            latchForVideoSaved = CountDownLatch(1)
+            latchForVideoRecording = CountDownLatch(5)
+            val videoFile = File.createTempFile("camerax-video", ".tmp").apply {
+                deleteOnExit()
+            }
+
+            completeVideoRecording(it, videoFile)
+            videoFile.delete()
+        }
+        // Assert: checks that images can be received by the ImageAnalysis.Analyzer
+        imageAnalysis?.let {
+            val analyzerFrameAvailableMonitor = ImageAnalysisImageAvailableMonitor()
+            it.setAnalyzer(
+                Executors.newSingleThreadExecutor(),
+                analyzerFrameAvailableMonitor.createAnalyzer()
+            )
+            analyzerFrameAvailableMonitor.awaitAvailableFramesAndAssert()
+        }
+    }
+
+    private fun startVideoRecording(videoCapture: VideoCapture<Recorder>, file: File):
+        Recording {
+        val recording = videoCapture.output
+            .prepareRecording(context, FileOutputOptions.Builder(file).build())
+            .start(CameraXExecutors.directExecutor(), videoRecordEventListener)
+
+        try {
+            // Waits for status event to proceed recording for a while.
+            assertThat(latchForVideoRecording.await(VIDEO_TIMEOUT_SEC, TimeUnit.SECONDS))
+                .isTrue()
+        } catch (ex: Exception) {
+            recording.stop()
+            throw ex
+        }
+
+        return recording
+    }
+
+    private fun completeVideoRecording(videoCapture: VideoCapture<Recorder>, file: File) {
+        val recording = startVideoRecording(videoCapture, file)
+
+        recording.stop()
+        // Waits for finalize event to saved file.
+        assertThat(latchForVideoSaved.await(VIDEO_TIMEOUT_SEC, TimeUnit.SECONDS)).isTrue()
+
+        // Checks if any error after recording finalized
+        Truth.assertWithMessage(TAG + "Finalize with error: ${finalize.error}, ${finalize.cause}.")
+            .that(finalize.hasError()).isFalse()
+    }
+
+    private class PreviewFrameAvailableMonitor {
+        private var isSurfaceTextureReleased = false
+        private val isSurfaceTextureReleasedLock = Any()
+
+        private var surfaceTextureLatch = CountDownLatch(1)
+        private var previewFrameCountDownLatch: CountDownLatch? = null
+
+        private val onFrameAvailableListener = object : SurfaceTexture.OnFrameAvailableListener {
+            private var complete = false
+
+            override fun onFrameAvailable(surfaceTexture: SurfaceTexture): Unit = runBlocking {
+
+                withContext(Dispatchers.Main) {
+                    synchronized(isSurfaceTextureReleasedLock) {
+                        if (!isSurfaceTextureReleased) {
+                            surfaceTexture.updateTexImage()
+                        }
+                    }
+                }
+
+                previewFrameCountDownLatch?.let {
+                    if (!complete) {
+                        it.countDown()
+                        if (it.count == 0L) {
+                            complete = true
+                        }
+                    }
+                }
+            }
+        }
+
+        private val frameAvailableHandler: Handler
+        private val frameAvailableHandlerThread = HandlerThread("FrameAvailable").also {
+            it.start()
+            frameAvailableHandler = Handler(it.looper)
+        }
+
+        fun createSurfaceTextureCallback(): SurfaceTextureProvider.SurfaceTextureCallback =
+            object : SurfaceTextureProvider.SurfaceTextureCallback {
+                override fun onSurfaceTextureReady(
+                    surfaceTexture: SurfaceTexture,
+                    resolution: Size
+                ) {
+                    if (texId == INVALID_TEX_ID) {
+                        texId = GLUtil.getTexIdFromGLContext()
+                    }
+                    surfaceTexture.attachToGLContext(texId)
+                    surfaceTexture.setOnFrameAvailableListener(
+                        onFrameAvailableListener,
+                        frameAvailableHandler
+                    )
+
+                    surfaceTextureLatch.countDown()
+                }
+
+                override fun onSafeToRelease(surfaceTexture: SurfaceTexture) {
+                    synchronized(isSurfaceTextureReleasedLock) {
+                        isSurfaceTextureReleased = true
+                        surfaceTexture.detachFromGLContext()
+                        surfaceTexture.release()
+                        frameAvailableHandlerThread.quitSafely()
+                    }
+                }
+            }
+
+        fun awaitSurfaceTextureReadyAndAssert(timeoutDurationMs: Long = 1000) {
+            assertThat(surfaceTextureLatch.await(timeoutDurationMs, TimeUnit.MILLISECONDS)).isTrue()
+        }
+
+        fun awaitAvailableFramesAndAssert(count: Int = 10, timeoutDurationMs: Long = 3000) {
+            previewFrameCountDownLatch = CountDownLatch(count)
+            assertThat(
+                previewFrameCountDownLatch!!.await(
+                    timeoutDurationMs,
+                    TimeUnit.MILLISECONDS
+                )
+            ).isTrue()
+        }
+    }
+
+    private class ImageCaptureCaptureSuccessMonitor {
+        private val captureSuccessCountDownLatch = CountDownLatch(1)
+
+        fun createCaptureCallback() = object : ImageCapture.OnImageCapturedCallback() {
+            override fun onCaptureSuccess(image: ImageProxy) {
+                image.close()
+                captureSuccessCountDownLatch.countDown()
+            }
+        }
+
+        fun awaitCaptureSuccessAndAssert(timeoutDurationMs: Long = 10000) {
+            assertThat(
+                captureSuccessCountDownLatch.await(
+                    timeoutDurationMs,
+                    TimeUnit.MILLISECONDS
+                )
+            ).isTrue()
+        }
+    }
+
+    private class ImageAnalysisImageAvailableMonitor {
+        private var analyzerFrameCountDownLatch: CountDownLatch? = null
+
+        fun createAnalyzer() = ImageAnalysis.Analyzer { image ->
+            image.close()
+            analyzerFrameCountDownLatch?.countDown()
+        }
+
+        fun awaitAvailableFramesAndAssert(count: Int = 10, timeoutDurationMs: Long = 3000) {
+            analyzerFrameCountDownLatch = CountDownLatch(count)
+            assertThat(
+                analyzerFrameCountDownLatch!!.await(
+                    timeoutDurationMs,
+                    TimeUnit.MILLISECONDS
+                )
+            ).isTrue()
+        }
+    }
+}
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 48349ae..0636c9b 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
@@ -56,8 +56,7 @@
 @RunWith(AndroidJUnit4::class)
 @LargeTest
 class ExistingActivityLifecycleTest {
-    private val mDevice =
-        UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+    private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
 
     @get:Rule
     val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
@@ -65,7 +64,7 @@
     )
 
     @get:Rule
-    val mPermissionRule: GrantPermissionRule =
+    val permissionRule: GrantPermissionRule =
         GrantPermissionRule.grant(
             Manifest.permission.WRITE_EXTERNAL_STORAGE,
             Manifest.permission.RECORD_AUDIO
@@ -99,16 +98,16 @@
         // recreated unexpectedly. This will also freeze the sensors until
         // mDevice.unfreezeRotation() in the tearDown() method. Any simulated rotations will be
         // explicitly initiated from within the test.
-        mDevice.setOrientationNatural()
+        device.setOrientationNatural()
     }
 
     @After
     fun tearDown() {
         // Unfreeze rotation so the device can choose the orientation via its own policy. Be nice
         // to other tests :)
-        mDevice.unfreezeRotation()
-        mDevice.pressHome()
-        mDevice.waitForIdle(HOME_TIMEOUT_MS)
+        device.unfreezeRotation()
+        device.pressHome()
+        device.waitForIdle(HOME_TIMEOUT_MS)
     }
 
     // Check if Preview screen is updated or not, after Destroy-Create lifecycle.
@@ -126,6 +125,27 @@
         }
     }
 
+    // Check ImageCapture to take pictures successfully, after the Destroy-Create lifecycle.
+    @Test
+    @RepeatRule.Repeat(times = 5)
+    fun checkImageCaptureAfterDestroyRecreate() {
+        with(ActivityScenario.launch(CameraXActivity::class.java)) { // Launch activity.
+            use {
+                // Arrange.
+                // Ensure ActivityScenario is cleaned up properly
+                // Wait for viewfinder to receive enough frames for its IdlingResource to idle.
+                waitForViewfinderIdle()
+
+                // Act. Destroy previous activity, launch new activity and check for view idle.
+                recreate()
+                waitForViewfinderIdle()
+
+                // Assert.
+                takePictureAndWaitForImageSavedIdle()
+            }
+        }
+    }
+
     // Check if Preview screen is updated or not, after Stop-Resume lifecycle.
     @Test
     @RepeatRule.Repeat(times = 5)
@@ -155,6 +175,29 @@
         }
     }
 
+    // Check ImageCapture to take pictures successfully, after Stop-Resume lifecycle.
+    @Test
+    @RepeatRule.Repeat(times = 5)
+    fun checkImageCaptureAfterStopResume() {
+        with(ActivityScenario.launch(CameraXActivity::class.java)) { // Launch activity.
+            use {
+                // Arrange.
+                // Ensure ActivityScenario is cleaned up properly
+                // Wait for viewfinder to receive enough frames for its IdlingResource to idle.
+                waitForViewfinderIdle()
+
+                for (i in 0..1) {
+                    // Act. Go through pause/resume then check.
+                    moveToState(CREATED)
+                    moveToState(RESUMED)
+
+                    // Assert.
+                    takePictureAndWaitForImageSavedIdle()
+                }
+            }
+        }
+    }
+
     // Check if Preview screen is updated or not, after toggling camera,
     // then a Destroy-Create lifecycle.
     @Test
@@ -189,6 +232,42 @@
         }
     }
 
+    // Check ImageCapture to take pictures successfully, after toggling camera,
+    // then a Destroy-Create lifecycle.
+    @Test
+    @RepeatRule.Repeat(times = 5)
+    fun checkImageCaptureAfterToggleCameraAndStopResume() = runBlocking {
+        // check have front camera
+        Assume.assumeTrue(
+            CameraUtil.hasCameraWithLensFacing(
+                CameraSelector.LENS_FACING_FRONT
+            )
+        )
+
+        with(ActivityScenario.launch(CameraXActivity::class.java)) { // Launch activity.
+            use {
+                // Arrange.
+                // Ensure ActivityScenario is cleaned up properly
+                // Wait for viewfinder to receive enough frames for its IdlingResource to idle.
+                waitForViewfinderIdle()
+
+                // Act. Switch camera.
+                Espresso.onView(ViewMatchers.withId(R.id.direction_toggle))
+                    .perform(ViewActions.click())
+
+                // Assert.
+                takePictureAndWaitForImageSavedIdle()
+
+                // Act. Go through pause/resume then check again.
+                moveToState(CREATED)
+                moveToState(RESUMED)
+
+                // Assert.
+                takePictureAndWaitForImageSavedIdle()
+            }
+        }
+    }
+
     // Check if Preview screen is updated or not, after rotate device, and Stop-Resume lifecycle.
     @Test
     @RepeatRule.Repeat(times = 5)
@@ -214,13 +293,43 @@
         }
     }
 
+    // Check ImageCapture to take pictures successfully, after rotate device, and Stop-Resume
+    // lifecycle.
+    @Test
+    @RepeatRule.Repeat(times = 5)
+    fun checkImageCaptureAfterRotateDeviceAndStopResume() {
+        with(ActivityScenario.launch(CameraXActivity::class.java)) { // Launch activity.
+            use {
+                // Arrange.
+                // Ensure ActivityScenario is cleaned up properly
+                // Wait for viewfinder to receive enough frames for its IdlingResource to idle.
+                waitForViewfinderIdle()
+
+                // Act.
+                // Rotate to the orientation left of natural and wait for the activity to be
+                // recreated.
+                rotateDeviceLeftAndWait()
+
+                // Get idling from the re-created activity.
+                withActivity { resetViewIdlingResource() }
+                waitForViewfinderIdle()
+                // Go through pause/resume then check again.
+                moveToState(CREATED)
+                moveToState(RESUMED)
+
+                // Assert.
+                takePictureAndWaitForImageSavedIdle()
+            }
+        }
+    }
+
     private fun rotateDeviceLeftAndWait() {
         // Create an ActivityMonitor to explicitly wait for the activity to be recreated after
         // rotating the device.
         val monitor =
             Instrumentation.ActivityMonitor(CameraXActivity::class.java.name, null, false)
         InstrumentationRegistry.getInstrumentation().addMonitor(monitor)
-        mDevice.setOrientationLeft()
+        device.setOrientationLeft()
         // Wait for the rotation to complete
         InstrumentationRegistry.getInstrumentation().waitForMonitorWithTimeout(
             monitor,
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureLatencyTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureLatencyTest.kt
new file mode 100644
index 0000000..552b6c28
--- /dev/null
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/ImageCaptureLatencyTest.kt
@@ -0,0 +1,167 @@
+/*
+ * 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.camera.integration.core
+
+import android.content.Context
+import androidx.camera.camera2.Camera2Config
+import androidx.camera.camera2.pipe.integration.CameraPipeConfig
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.CameraXConfig
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageProxy
+import androidx.camera.core.Logger
+import androidx.camera.core.internal.CameraUseCaseAdapter
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.LabTestRule
+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
+import kotlinx.coroutines.withContext
+import org.junit.After
+import org.junit.Assert.assertTrue
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+private const val NUM_IMAGES = 10
+
+/**
+ * Profiles the ImageCapture performance for capturing images in different capture modes.
+ *
+ * Time measurement is taken from the time the capture request sent to when an ImageProxy is
+ * returned. Saving an image to disk is not counted.
+ *
+ * Measurement is the total time for capturing NUM_IMAGES images.
+ */
+@LargeTest
+@RunWith(Parameterized::class)
+class ImageCaptureLatencyTest(
+    private val implName: String,
+    private val cameraXConfig: CameraXConfig
+) {
+
+    @get:Rule
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(cameraXConfig)
+    )
+
+    @get:Rule
+    val labTest = LabTestRule()
+
+    private val context = ApplicationProvider.getApplicationContext<Context>()
+    private lateinit var camera: CameraUseCaseAdapter
+    private lateinit var cameraProvider: ProcessCameraProvider
+    private lateinit var fakeLifecycleOwner: FakeLifecycleOwner
+
+    companion object {
+        private const val TAG = "ImageCaptureLatencyTest"
+        @JvmStatic
+        @Parameterized.Parameters(name = "{0}")
+        fun data() = listOf(
+            arrayOf(Camera2Config::class.simpleName, Camera2Config.defaultConfig()),
+            arrayOf(CameraPipeConfig::class.simpleName, CameraPipeConfig.defaultConfig())
+        )
+    }
+
+    @Before
+    fun setUp() = runBlocking {
+        Assume.assumeTrue(CameraUtil.hasCameraWithLensFacing(CameraSelector.LENS_FACING_BACK))
+        ProcessCameraProvider.configureInstance(cameraXConfig)
+        cameraProvider = ProcessCameraProvider.getInstance(context).get(10, TimeUnit.SECONDS)
+
+        withContext(Dispatchers.Main) {
+            fakeLifecycleOwner = FakeLifecycleOwner()
+            fakeLifecycleOwner.startAndResume()
+        }
+    }
+
+    @After
+    fun tearDown() = runBlocking {
+        if (::cameraProvider.isInitialized) {
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+                cameraProvider.shutdown()
+            }
+        }
+    }
+
+    @Test
+    fun imageCaptureMeasurementZsl() {
+        imageCaptureMeasurement(ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG)
+    }
+
+    @Test
+    fun imageCaptureMeasurementMinimizeLatency() {
+        imageCaptureMeasurement(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
+    }
+
+    @Test
+    fun imageCaptureMeasurementMaximizeQuality() {
+        imageCaptureMeasurement(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
+    }
+
+    private fun imageCaptureMeasurement(captureMode: Int) {
+
+        val imageCapture = ImageCapture.Builder().setCaptureMode(captureMode).build()
+
+        camera = CameraUtil.createCameraAndAttachUseCase(
+            context,
+            CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build(),
+            imageCapture
+        )
+
+        // Skip if capture mode is ZSL and the device doesn't support ZSL
+        if ((captureMode == ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG) &&
+            !camera.cameraInfo.isZslSupported) {
+            Logger.d(TAG, "Skipping due to no ZSL support")
+            return
+        }
+
+        val startTimeMillis = System.currentTimeMillis()
+
+        val countDownLatch = CountDownLatch(NUM_IMAGES)
+
+        for (i in 1..NUM_IMAGES) {
+            imageCapture.takePicture(
+                Dispatchers.Main.asExecutor(),
+                object : ImageCapture.OnImageCapturedCallback() {
+                    override fun onCaptureSuccess(image: ImageProxy) {
+                        image.close()
+                        countDownLatch.countDown()
+                    }
+                })
+        }
+
+        assertTrue(countDownLatch.await(60, TimeUnit.SECONDS))
+
+        val duration = System.currentTimeMillis() - startTimeMillis
+
+        // This log is used to profile the ImageCapture performance. The log parser identifies the log
+        // pattern "Image capture performance profiling" in the device output log.
+        Logger.d(TAG,
+            "Image capture performance profiling, duration: [$duration] capture mode: $captureMode")
+    }
+}
\ No newline at end of file
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 31dd861..bd8a40d 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
@@ -78,6 +78,7 @@
 import androidx.test.filters.SdkSuppress
 import androidx.test.rule.GrantPermissionRule
 import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
 import java.io.ByteArrayInputStream
 import java.io.File
 import java.io.FileOutputStream
@@ -86,10 +87,12 @@
 import java.util.concurrent.atomic.AtomicInteger
 import kotlin.math.abs
 import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.Deferred
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
 import kotlinx.coroutines.withTimeout
+import kotlinx.coroutines.withTimeoutOrNull
 import org.junit.After
 import org.junit.Assume.assumeFalse
 import org.junit.Assume.assumeNotNull
@@ -1610,6 +1613,47 @@
         simpleCaptureProcessor.close()
     }
 
+    @Test
+    fun unbindPreview_imageCapturingShouldSuccess() = runBlocking {
+        skipTestOnCameraPipeConfig()
+
+        // Arrange.
+        val imageCapture = ImageCapture.Builder().build()
+        val previewStreamReceived = CompletableDeferred<Boolean>()
+        val preview = Preview.Builder().also {
+            Camera2Interop.Extender(it).setSessionCaptureCallback(
+                object : CaptureCallback() {
+                    override fun onCaptureCompleted(
+                        session: CameraCaptureSession,
+                        request: CaptureRequest,
+                        result: TotalCaptureResult
+                    ) {
+                        previewStreamReceived.complete(true)
+                    }
+                }
+            )
+        }.build()
+        withContext(Dispatchers.Main) {
+            preview.setSurfaceProvider(SurfaceTextureProvider.createSurfaceTextureProvider())
+            cameraProvider.bindToLifecycle(
+                fakeLifecycleOwner, BACK_SELECTOR, imageCapture, preview)
+        }
+        assertWithMessage("Preview doesn't start").that(
+            previewStreamReceived.awaitWithTimeoutOrNull()
+        ).isTrue()
+
+        // Act.
+        val callback = FakeImageCaptureCallback(capturesCount = 1)
+        withContext(Dispatchers.Main) {
+            // Test the reproduce step in b/235119898
+            cameraProvider.unbind(preview)
+            imageCapture.takePicture(mainExecutor, callback)
+        }
+
+        // Assert.
+        callback.awaitCapturesAndAssert(capturedImagesCount = 1)
+    }
+
     private fun createNonRotatedConfiguration(): ImageCaptureConfig {
         // Create a configuration with target rotation that matches the sensor rotation.
         // This assumes a back-facing camera (facing away from screen)
@@ -1785,4 +1829,12 @@
             deferredItems.forEach { it.await() }
         }
     }
+
+    private suspend fun <T> Deferred<T>.awaitWithTimeoutOrNull(
+        timeMillis: Long = TimeUnit.SECONDS.toMillis(5)
+    ): T? {
+        return withTimeoutOrNull(timeMillis) {
+            await()
+        }
+    }
 }
\ No newline at end of file
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/OpenCloseCameraStressTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/OpenCloseCameraStressTest.kt
new file mode 100644
index 0000000..49b393c
--- /dev/null
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/OpenCloseCameraStressTest.kt
@@ -0,0 +1,239 @@
+/*
+ * 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.camera.integration.core
+
+import android.content.Context
+import androidx.camera.camera2.Camera2Config
+import androidx.camera.core.Camera
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.CameraState
+import androidx.camera.core.ImageAnalysis
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.Preview
+import androidx.camera.integration.core.util.StressTestUtil.STRESS_TEST_OPERATION_REPEAT_COUNT
+import androidx.camera.integration.core.util.StressTestUtil.STRESS_TEST_REPEAT_COUNT
+import androidx.camera.integration.core.util.StressTestUtil.createCameraSelectorById
+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.camera.video.Recorder
+import androidx.camera.video.VideoCapture
+import androidx.lifecycle.Observer
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.testutils.RepeatRule
+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
+import org.junit.After
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+@SdkSuppress(minSdkVersion = 21)
+class OpenCloseCameraStressTest(
+    private val cameraId: String
+) {
+    @get:Rule
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
+
+    @get:Rule
+    val labTest: LabTestRule = LabTestRule()
+
+    @get:Rule
+    val repeatRule = RepeatRule()
+
+    private val context = ApplicationProvider.getApplicationContext<Context>()
+
+    private lateinit var cameraProvider: ProcessCameraProvider
+    private lateinit var camera: Camera
+    private lateinit var cameraIdCameraSelector: CameraSelector
+    private lateinit var preview: Preview
+    private lateinit var imageCapture: ImageCapture
+    private lateinit var lifecycleOwner: FakeLifecycleOwner
+
+    @Before
+    fun setUp(): Unit = runBlocking {
+        cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
+
+        cameraIdCameraSelector = createCameraSelectorById(cameraId)
+
+        camera = withContext(Dispatchers.Main) {
+            lifecycleOwner = FakeLifecycleOwner()
+            lifecycleOwner.startAndResume()
+            cameraProvider.bindToLifecycle(lifecycleOwner, cameraIdCameraSelector)
+        }
+
+        preview = Preview.Builder().build()
+        withContext(Dispatchers.Main) {
+            preview.setSurfaceProvider(SurfaceTextureProvider.createSurfaceTextureProvider())
+        }
+        imageCapture = ImageCapture.Builder().build()
+    }
+
+    @After
+    fun cleanUp(): Unit = runBlocking {
+        if (::cameraProvider.isInitialized) {
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+                cameraProvider.shutdown()[10000, TimeUnit.MILLISECONDS]
+            }
+        }
+    }
+
+    companion object {
+        @JvmStatic
+        @get:Parameterized.Parameters(name = "cameraId = {0}")
+        val parameters: Collection<String>
+            get() = CameraUtil.getBackwardCompatibleCameraIdListOrThrow()
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCameraStressTest_withPreviewImageCapture(): Unit = runBlocking {
+        bindUseCase_unbindAll_toCheckCameraState_repeatedly(preview, imageCapture)
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCameraStressTest_withPreviewImageCaptureImageAnalysis(): Unit = runBlocking {
+        val imageAnalysis = ImageAnalysis.Builder().build()
+        assumeTrue(camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis))
+        bindUseCase_unbindAll_toCheckCameraState_repeatedly(
+            preview,
+            imageCapture,
+            imageAnalysis = imageAnalysis
+        )
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCameraStressTest_withPreviewVideoCapture(): Unit = runBlocking {
+        val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+        bindUseCase_unbindAll_toCheckCameraState_repeatedly(preview, videoCapture = videoCapture)
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCameraStressTest_withPreviewVideoCaptureImageCapture(): Unit = runBlocking {
+        val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+        assumeTrue(camera.isUseCasesCombinationSupported(preview, videoCapture, imageCapture))
+        bindUseCase_unbindAll_toCheckCameraState_repeatedly(
+            preview,
+            videoCapture = videoCapture,
+            imageCapture = imageCapture
+        )
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCameraStressTest_withPreviewVideoCaptureImageAnalysis(): Unit = runBlocking {
+        val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+        val imageAnalysis = ImageAnalysis.Builder().build()
+        assumeTrue(camera.isUseCasesCombinationSupported(preview, videoCapture, imageAnalysis))
+        bindUseCase_unbindAll_toCheckCameraState_repeatedly(
+            preview,
+            videoCapture = videoCapture,
+            imageAnalysis = imageAnalysis
+        )
+    }
+
+    /**
+     * Repeatedly binds use cases, unbind all to check whether the camera can be opened and closed
+     * successfully by monitoring the camera state events.
+     *
+     * <p>This function checks the nullabilities of the input ImageCapture, VideoCapture and
+     * ImageAnalysis to determine whether the use cases will be bound together to run the test.
+     */
+    private fun bindUseCase_unbindAll_toCheckCameraState_repeatedly(
+        preview: Preview,
+        imageCapture: ImageCapture? = null,
+        videoCapture: VideoCapture<Recorder>? = null,
+        imageAnalysis: ImageAnalysis? = null,
+        repeatCount: Int = STRESS_TEST_OPERATION_REPEAT_COUNT
+    ): Unit = runBlocking {
+        for (i in 1..repeatCount) {
+            val openCameraLatch = CountDownLatch(1)
+            val closeCameraLatch = CountDownLatch(1)
+            val observer = Observer<CameraState> { state ->
+                if (state.type == CameraState.Type.OPEN) {
+                    openCameraLatch.countDown()
+                } else if (state.type == CameraState.Type.CLOSED) {
+                    closeCameraLatch.countDown()
+                }
+            }
+
+            withContext(Dispatchers.Main) {
+                // Arrange: sets up CameraState observer
+                camera.cameraInfo.cameraState.observe(lifecycleOwner, observer)
+
+                // VideoCapture needs to be recreated everytime until b/212654991 is fixed
+                var newVideoCapture: VideoCapture<Recorder>? = null
+                videoCapture?.let {
+                    newVideoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+                }
+
+                // Act: binds use cases
+                cameraProvider.bindToLifecycle(
+                    lifecycleOwner,
+                    cameraIdCameraSelector,
+                    *listOfNotNull(
+                        preview,
+                        imageCapture,
+                        newVideoCapture,
+                        imageAnalysis
+                    ).toTypedArray()
+                )
+            }
+
+            // Assert: checks the CameraState.Type.OPEN can be received
+            assertThat(openCameraLatch.await(3000, TimeUnit.MILLISECONDS)).isTrue()
+
+            // Act: unbinds all use cases
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+            }
+
+            // Assert: checks the CameraState.Type.CLOSED can be received
+            assertThat(closeCameraLatch.await(3000, TimeUnit.MILLISECONDS)).isTrue()
+
+            // Clean it up.
+            withContext(Dispatchers.Main) {
+                camera.cameraInfo.cameraState.removeObserver(observer)
+            }
+        }
+    }
+}
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/OpenCloseCaptureSessionStressTest.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/OpenCloseCaptureSessionStressTest.kt
new file mode 100644
index 0000000..ea8be15
--- /dev/null
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/OpenCloseCaptureSessionStressTest.kt
@@ -0,0 +1,278 @@
+/*
+ * 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.camera.integration.core
+
+import android.content.Context
+import androidx.camera.camera2.Camera2Config
+import androidx.camera.camera2.impl.Camera2ImplConfig
+import androidx.camera.camera2.impl.CameraEventCallback
+import androidx.camera.camera2.impl.CameraEventCallbacks
+import androidx.camera.core.Camera
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.ImageAnalysis
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.Preview
+import androidx.camera.core.impl.CaptureConfig
+import androidx.camera.integration.core.util.StressTestUtil.STRESS_TEST_OPERATION_REPEAT_COUNT
+import androidx.camera.integration.core.util.StressTestUtil.STRESS_TEST_REPEAT_COUNT
+import androidx.camera.integration.core.util.StressTestUtil.createCameraSelectorById
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.LabTestRule
+import androidx.camera.testing.SurfaceTextureProvider
+import androidx.camera.testing.fakes.FakeLifecycleOwner
+import androidx.camera.video.Recorder
+import androidx.camera.video.VideoCapture
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import androidx.testutils.RepeatRule
+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
+import org.junit.After
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+@SdkSuppress(minSdkVersion = 21)
+class OpenCloseCaptureSessionStressTest(
+    private val cameraId: String
+) {
+    @get:Rule
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        CameraUtil.PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
+
+    @get:Rule
+    val labTest: LabTestRule = LabTestRule()
+
+    @get:Rule
+    val repeatRule = RepeatRule()
+
+    private val context = ApplicationProvider.getApplicationContext<Context>()
+
+    private lateinit var cameraProvider: ProcessCameraProvider
+    private lateinit var camera: Camera
+    private lateinit var cameraIdCameraSelector: CameraSelector
+    private lateinit var preview: Preview
+    private lateinit var imageCapture: ImageCapture
+    private lateinit var lifecycleOwner: FakeLifecycleOwner
+    private val cameraEventMonitor = CameraEventMonitor()
+
+    @Before
+    fun setUp(): Unit = runBlocking {
+        cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
+
+        cameraIdCameraSelector = createCameraSelectorById(cameraId)
+
+        camera = withContext(Dispatchers.Main) {
+            lifecycleOwner = FakeLifecycleOwner()
+            lifecycleOwner.startAndResume()
+            cameraProvider.bindToLifecycle(lifecycleOwner, cameraIdCameraSelector)
+        }
+
+        // Creates the Preview with the CameraEventMonitor to monitor whether the event callbacks
+        // are called.
+        preview = createPreviewWithCameraEventMonitor(cameraEventMonitor)
+        withContext(Dispatchers.Main) {
+            preview.setSurfaceProvider(SurfaceTextureProvider.createSurfaceTextureProvider())
+        }
+        imageCapture = ImageCapture.Builder().build()
+    }
+
+    @After
+    fun cleanUp(): Unit = runBlocking {
+        if (::cameraProvider.isInitialized) {
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+                cameraProvider.shutdown()[10000, TimeUnit.MILLISECONDS]
+            }
+        }
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCaptureSessionStressTest_withPreviewImageCapture(): Unit = runBlocking {
+        bindUseCase_unbindAll_toCheckCameraEvent_repeatedly(preview, imageCapture)
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCaptureSessionStressTest_withPreviewImageCaptureImageAnalysis(): Unit =
+        runBlocking {
+            val imageAnalysis = ImageAnalysis.Builder().build()
+            assumeTrue(camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis))
+            bindUseCase_unbindAll_toCheckCameraEvent_repeatedly(
+                preview,
+                imageCapture,
+                imageAnalysis = imageAnalysis
+            )
+        }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCaptureSessionStressTest_withPreviewVideoCapture(): Unit =
+        runBlocking {
+            val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+            bindUseCase_unbindAll_toCheckCameraEvent_repeatedly(
+                preview,
+                videoCapture = videoCapture
+            )
+        }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCaptureSessionStressTest_withPreviewVideoCaptureImageCapture(): Unit =
+        runBlocking {
+            val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+            assumeTrue(camera.isUseCasesCombinationSupported(preview, videoCapture, imageCapture))
+            bindUseCase_unbindAll_toCheckCameraEvent_repeatedly(
+                preview,
+                videoCapture = videoCapture,
+                imageCapture = imageCapture
+            )
+        }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCaptureSessionStressTest_withPreviewVideoCaptureImageAnalysis(): Unit =
+        runBlocking {
+            val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+            val imageAnalysis = ImageAnalysis.Builder().build()
+            assumeTrue(camera.isUseCasesCombinationSupported(preview, videoCapture, imageAnalysis))
+            bindUseCase_unbindAll_toCheckCameraEvent_repeatedly(
+                preview,
+                videoCapture = videoCapture,
+                imageAnalysis = imageAnalysis
+            )
+        }
+
+    /**
+     * Repeatedly binds use cases, unbind all to check whether the capture session can be opened
+     * and closed successfully by monitoring the CameraEvent callbacks.
+     *
+     * <p>This function checks the nullabilities of the input ImageCapture, VideoCapture and
+     * ImageAnalysis to determine whether the use cases will be bound together to run the test.
+     */
+    private fun bindUseCase_unbindAll_toCheckCameraEvent_repeatedly(
+        preview: Preview,
+        imageCapture: ImageCapture? = null,
+        videoCapture: VideoCapture<Recorder>? = null,
+        imageAnalysis: ImageAnalysis? = null,
+        repeatCount: Int = STRESS_TEST_OPERATION_REPEAT_COUNT
+    ): Unit = runBlocking {
+        for (i in 1..repeatCount) {
+            // Arrange: resets the camera event monitor
+            cameraEventMonitor.reset()
+
+            withContext(Dispatchers.Main) {
+                // VideoCapture needs to be recreated everytime until b/212654991 is fixed
+                var newVideoCapture: VideoCapture<Recorder>? = null
+                videoCapture?.let {
+                    newVideoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+                }
+
+                // Act: binds use cases
+                cameraProvider.bindToLifecycle(
+                    lifecycleOwner,
+                    cameraIdCameraSelector,
+                    *listOfNotNull(
+                        preview,
+                        imageCapture,
+                        newVideoCapture,
+                        imageAnalysis
+                    ).toTypedArray()
+                )
+            }
+
+            // Assert: checks the CameraEvent#onEnableSession callback function is called
+            cameraEventMonitor.awaitSessionEnabledAndAssert()
+
+            // Act: unbinds all use cases
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+            }
+
+            // Assert: checks the CameraEvent#onSessionDisabled callback function is called
+            cameraEventMonitor.awaitSessionDisabledAndAssert()
+        }
+    }
+
+    companion object {
+        @JvmStatic
+        @get:Parameterized.Parameters(name = "cameraId = {0}")
+        val parameters: Collection<String>
+            get() = CameraUtil.getBackwardCompatibleCameraIdListOrThrow()
+    }
+
+    private fun createPreviewWithCameraEventMonitor(
+        cameraEventMonitor: CameraEventMonitor
+    ): Preview {
+        val builder = Preview.Builder()
+
+        Camera2ImplConfig.Extender(builder)
+            .setCameraEventCallback(CameraEventCallbacks(cameraEventMonitor))
+
+        return builder.build()
+    }
+
+    /**
+     * An implementation of CameraEventCallback to monitor whether the camera event callbacks are
+     * called properly or not.
+     */
+    private class CameraEventMonitor : CameraEventCallback() {
+        private var sessionEnabledLatch = CountDownLatch(1)
+        private var sessionDisabledLatch = CountDownLatch(1)
+
+        override fun onEnableSession(): CaptureConfig? {
+            sessionEnabledLatch.countDown()
+            return null
+        }
+
+        override fun onDisableSession(): CaptureConfig? {
+            sessionDisabledLatch.countDown()
+            return null
+        }
+
+        fun reset() {
+            sessionEnabledLatch = CountDownLatch(1)
+            sessionDisabledLatch = CountDownLatch(1)
+        }
+
+        fun awaitSessionEnabledAndAssert() {
+            assertThat(sessionEnabledLatch.await(3000, TimeUnit.MILLISECONDS)).isTrue()
+        }
+
+        fun awaitSessionDisabledAndAssert() {
+            assertThat(sessionDisabledLatch.await(3000, TimeUnit.MILLISECONDS)).isTrue()
+        }
+    }
+}
diff --git a/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/util/StressTestUtil.kt b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/util/StressTestUtil.kt
new file mode 100644
index 0000000..31bd201
--- /dev/null
+++ b/camera/integration-tests/coretestapp/src/androidTest/java/androidx/camera/integration/core/util/StressTestUtil.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.camera.integration.core.util
+
+import androidx.annotation.OptIn
+import androidx.camera.camera2.interop.Camera2CameraInfo
+import androidx.camera.camera2.interop.ExperimentalCamera2Interop
+import androidx.camera.core.CameraFilter
+import androidx.camera.core.CameraInfo
+import androidx.camera.core.CameraSelector
+
+object StressTestUtil {
+
+    @JvmStatic
+    @OptIn(ExperimentalCamera2Interop::class)
+    fun createCameraSelectorById(cameraId: String) =
+        CameraSelector.Builder().addCameraFilter(CameraFilter { cameraInfos ->
+            cameraInfos.forEach {
+                if (Camera2CameraInfo.from(it).cameraId.equals(cameraId)) {
+                    return@CameraFilter listOf<CameraInfo>(it)
+                }
+            }
+
+            throw IllegalArgumentException("No camera can be find for id: $cameraId")
+        }).build()
+
+    /**
+     * Stress test repeat count to run the test
+     */
+    const val STRESS_TEST_REPEAT_COUNT = 2
+
+    /**
+     * Stress test target testing operation count.
+     *
+     * <p>The target testing operation might be:
+     * <ul>
+     *     <li> Open and close camera
+     *     <li> Open and close capture session
+     *     <li> Bind and unbind use cases
+     *     <li> Pause and resume lifecycle owner
+     *     <li> Switch cameras
+     *     <li> Switch extension modes
+     * </ul>
+     *
+     */
+    const val STRESS_TEST_OPERATION_REPEAT_COUNT = 10
+}
\ No newline at end of file
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
index c44d3c3..afabb4a 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
@@ -646,12 +646,6 @@
                                     @Override
                                     public void onError(@NonNull ImageCaptureException exception) {
                                         Log.e(TAG, "Failed to save image.", exception.getCause());
-                                        try {
-                                            mImageSavedIdlingResource.decrement();
-                                        } catch (IllegalStateException e) {
-                                            Log.e(TAG, "Error: unexpected onImageSaved "
-                                                    + "callback received. Continuing.");
-                                        }
                                     }
                                 });
                     }
@@ -980,6 +974,12 @@
         // Clear listening frame update before unbind all.
         mPreviewRenderer.clearFrameUpdateListener();
 
+        // Remove ZoomState observer from old CameraInfo to prevent from receiving event from old
+        // CameraInfo
+        if (mCamera != null) {
+            mCamera.getCameraInfo().getZoomState().removeObservers(this);
+        }
+
         // Stop video recording if exists.
         if (mRecordUi.getState() == RecordUi.State.RECORDING
                 || mRecordUi.getState() == RecordUi.State.PAUSED) {
diff --git a/camera/integration-tests/diagnosetestapp/src/main/AndroidManifest.xml b/camera/integration-tests/diagnosetestapp/src/main/AndroidManifest.xml
index 40312a1..83f7ba3 100644
--- a/camera/integration-tests/diagnosetestapp/src/main/AndroidManifest.xml
+++ b/camera/integration-tests/diagnosetestapp/src/main/AndroidManifest.xml
@@ -15,8 +15,7 @@
   limitations under the License.
   -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.camera.integration.diagnose">>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/BindUnbindUseCasesStressTest.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/BindUnbindUseCasesStressTest.kt
index 9ebe2c5..abf8aae 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/BindUnbindUseCasesStressTest.kt
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/BindUnbindUseCasesStressTest.kt
@@ -28,7 +28,6 @@
 import androidx.camera.core.ImageCapture
 import androidx.camera.core.ImageProxy
 import androidx.camera.core.Preview
-import androidx.camera.extensions.ExtensionMode
 import androidx.camera.extensions.ExtensionsManager
 import androidx.camera.integration.extensions.util.ExtensionsTestUtil
 import androidx.camera.integration.extensions.util.ExtensionsTestUtil.STRESS_TEST_OPERATION_REPEAT_COUNT
@@ -60,6 +59,9 @@
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
 
+private const val INVALID_TEX_ID = -1
+private var texId = INVALID_TEX_ID
+
 @LargeTest
 @RunWith(Parameterized::class)
 @SdkSuppress(minSdkVersion = 21)
@@ -87,15 +89,11 @@
     private lateinit var extensionCameraSelector: CameraSelector
     private lateinit var preview: Preview
     private lateinit var imageCapture: ImageCapture
-    private lateinit var imageAnalysis: ImageAnalysis
-    private var isImageAnalysisSupported = false
     private lateinit var lifecycleOwner: FakeLifecycleOwner
 
     @Before
     fun setUp(): Unit = runBlocking {
-        if (extensionMode != ExtensionMode.NONE) {
-            assumeTrue(ExtensionsTestUtil.isTargetDeviceAvailableForExtensions())
-        }
+        assumeTrue(ExtensionsTestUtil.isTargetDeviceAvailableForExtensions())
         cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
         extensionsManager = ExtensionsManager.getInstanceAsync(
             context,
@@ -118,10 +116,6 @@
 
         preview = Preview.Builder().build()
         imageCapture = ImageCapture.Builder().build()
-        imageAnalysis = ImageAnalysis.Builder().build()
-
-        isImageAnalysisSupported =
-            camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis)
     }
 
     @After
@@ -142,18 +136,46 @@
         @JvmStatic
         @get:Parameterized.Parameters(name = "cameraId = {0}, extensionMode = {1}")
         val parameters: Collection<Array<Any>>
-            get() = ExtensionsTestUtil.getAllCameraIdModeCombinations()
+            get() = ExtensionsTestUtil.getAllCameraIdExtensionModeCombinations()
     }
 
     @LabTestRule.LabTestOnly
     @Test
     @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
-    fun bindUnbindUseCasesTenTimes_canCaptureImageInEachTime(): Unit = runBlocking {
-        for (i in 1..STRESS_TEST_OPERATION_REPEAT_COUNT) {
-            val previewFrameAvailableMonitor = PreviewFrameAvailableMonitor()
-            val imageCaptureCaptureSuccessMonitor = ImageCaptureCaptureSuccessMonitor()
-            var analyzerFrameAvailableMonitor: ImageAnalysisImageAvailableMonitor? = null
+    fun bindUnbindUseCasesTenTimes_canCaptureImageInEachTime_withPreviewImageCapture(): Unit =
+        runBlocking {
+            bindUseCases_checkOutput_thenUnbindAll_repeatedly(preview, imageCapture)
+        }
 
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun bindUnbindUseCasesTenTimes_canCaptureImageInEachTime_withPreviewImageCaptureImageAnalysis():
+        Unit = runBlocking {
+        val imageAnalysis = ImageAnalysis.Builder().build()
+        assumeTrue(camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis))
+        bindUseCases_checkOutput_thenUnbindAll_repeatedly(preview, imageCapture, imageAnalysis)
+    }
+
+    /**
+     * Repeatedly binds use cases, checks the input use cases' capture functions can work well, and
+     * unbind all use cases.
+     *
+     * <p>This function checks the nullability of the input ImageAnalysis to determine whether it
+     * will be bound together to run the test.
+     */
+    private fun bindUseCases_checkOutput_thenUnbindAll_repeatedly(
+        preview: Preview,
+        imageCapture: ImageCapture,
+        imageAnalysis: ImageAnalysis? = null,
+        repeatCount: Int = STRESS_TEST_OPERATION_REPEAT_COUNT
+    ): Unit = runBlocking {
+        for (i in 1..repeatCount) {
+            // Arrange.
+            // Sets up Preview frame available monitor
+            val previewFrameAvailableMonitor = PreviewFrameAvailableMonitor()
+
+            // Act: binds use cases
             withContext(Dispatchers.Main) {
                 preview.setSurfaceProvider(
                     SurfaceTextureProvider.createSurfaceTextureProvider(
@@ -161,42 +183,36 @@
                     )
                 )
 
-                if (isImageAnalysisSupported) {
-                    analyzerFrameAvailableMonitor = ImageAnalysisImageAvailableMonitor()
-                    imageAnalysis.setAnalyzer(
-                        Executors.newSingleThreadExecutor(),
-                        analyzerFrameAvailableMonitor!!.createAnalyzer()
-                    )
-
-                    cameraProvider.bindToLifecycle(
-                        lifecycleOwner,
-                        extensionCameraSelector,
-                        preview,
-                        imageCapture,
-                        imageAnalysis
-                    )
-                } else {
-                    cameraProvider.bindToLifecycle(
-                        lifecycleOwner,
-                        extensionCameraSelector,
-                        preview,
-                        imageCapture
-                    )
-                }
+                cameraProvider.bindToLifecycle(
+                    lifecycleOwner,
+                    extensionCameraSelector,
+                    *listOfNotNull(preview, imageCapture, imageAnalysis).toTypedArray()
+                )
             }
 
+            // Assert: checks that Preview frames can be received
             previewFrameAvailableMonitor.awaitSurfaceTextureReadyAndAssert()
             previewFrameAvailableMonitor.awaitAvailableFramesAndAssert()
 
+            val imageCaptureCaptureSuccessMonitor = ImageCaptureCaptureSuccessMonitor()
             imageCapture.takePicture(
                 Executors.newSingleThreadExecutor(),
                 imageCaptureCaptureSuccessMonitor.createCaptureCallback()
             )
 
+            // Assert: checks that the captured image of ImageCapture can be received
             imageCaptureCaptureSuccessMonitor.awaitCaptureSuccessAndAssert()
 
-            analyzerFrameAvailableMonitor?.awaitAvailableFramesAndAssert()
+            // Assert: checks that images can be received by the ImageAnalysis.Analyzer
+            imageAnalysis?.let {
+                val analyzerFrameAvailableMonitor = ImageAnalysisImageAvailableMonitor()
+                it.setAnalyzer(
+                    Executors.newSingleThreadExecutor(),
+                    analyzerFrameAvailableMonitor.createAnalyzer()
+                )
+            }
 
+            // Clean it up.
             withContext(Dispatchers.Main) {
                 cameraProvider.unbindAll()
             }
@@ -206,15 +222,42 @@
     @LabTestRule.LabTestOnly
     @Test
     @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
-    fun canCaptureImage_afterBindUnbindUseCasesTenTimes(): Unit = runBlocking {
+    fun canCaptureImage_afterBindUnbindUseCasesTenTimes_withPreviewImageCapture(): Unit =
+        runBlocking {
+            bindUseCases_unbindAll_repeatedly_thenCheckOutput(preview, imageCapture)
+        }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun canCaptureImage_afterBindUnbindUseCasesTenTimes_withPreviewImageCaptureImageAnalysis():
+        Unit = runBlocking {
+            val imageAnalysis = ImageAnalysis.Builder().build()
+            assumeTrue(camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis))
+        bindUseCases_unbindAll_repeatedly_thenCheckOutput(preview, imageCapture, imageAnalysis)
+        }
+
+    /**
+     * Repeatedly binds use cases and unbind all, then checks the input use cases' capture
+     * functions can work well.
+     *
+     * <p>This function checks the nullability of the input ImageAnalysis to determine whether it
+     * will be bound together to run the test.
+     */
+    private fun bindUseCases_unbindAll_repeatedly_thenCheckOutput(
+        preview: Preview,
+        imageCapture: ImageCapture,
+        imageAnalysis: ImageAnalysis? = null,
+        repeatCount: Int = STRESS_TEST_OPERATION_REPEAT_COUNT
+    ): Unit = runBlocking {
         lateinit var previewFrameAvailableMonitor: PreviewFrameAvailableMonitor
-        lateinit var imageCaptureCaptureSuccessMonitor: ImageCaptureCaptureSuccessMonitor
-        var analyzerFrameAvailableMonitor: ImageAnalysisImageAvailableMonitor? = null
 
-        for (i in 1..STRESS_TEST_OPERATION_REPEAT_COUNT) {
+        for (i in 1..repeatCount) {
+            // Arrange.
+            // Sets up Preview frame available monitor
             previewFrameAvailableMonitor = PreviewFrameAvailableMonitor()
-            imageCaptureCaptureSuccessMonitor = ImageCaptureCaptureSuccessMonitor()
 
+            // Act: binds use cases
             withContext(Dispatchers.Main) {
                 preview.setSurfaceProvider(
                     SurfaceTextureProvider.createSurfaceTextureProvider(
@@ -222,48 +265,42 @@
                     )
                 )
 
-                if (isImageAnalysisSupported) {
-                    analyzerFrameAvailableMonitor = ImageAnalysisImageAvailableMonitor()
-                    imageAnalysis.setAnalyzer(
-                        Executors.newSingleThreadExecutor(),
-                        analyzerFrameAvailableMonitor!!.createAnalyzer()
-                    )
+                cameraProvider.bindToLifecycle(
+                    lifecycleOwner,
+                    extensionCameraSelector,
+                    *listOfNotNull(preview, imageCapture, imageAnalysis).toTypedArray()
+                )
 
-                    cameraProvider.bindToLifecycle(
-                        lifecycleOwner,
-                        extensionCameraSelector,
-                        preview,
-                        imageCapture,
-                        imageAnalysis
-                    )
-                } else {
-                    cameraProvider.bindToLifecycle(
-                        lifecycleOwner,
-                        extensionCameraSelector,
-                        preview,
-                        imageCapture
-                    )
-                }
-            }
-
-            withContext(Dispatchers.Main) {
-                if (i != STRESS_TEST_OPERATION_REPEAT_COUNT) {
+                // Clean it up: do not unbind at the last time
+                if (i != repeatCount) {
                     cameraProvider.unbindAll()
                 }
             }
         }
 
+        // Assert: checks that Preview frames can be received
         previewFrameAvailableMonitor.awaitSurfaceTextureReadyAndAssert()
         previewFrameAvailableMonitor.awaitAvailableFramesAndAssert()
 
+        val imageCaptureCaptureSuccessMonitor = ImageCaptureCaptureSuccessMonitor()
         imageCapture.takePicture(
             Executors.newSingleThreadExecutor(),
             imageCaptureCaptureSuccessMonitor.createCaptureCallback()
         )
 
+        // Assert: checks that the captured image of ImageCapture can be received
         imageCaptureCaptureSuccessMonitor.awaitCaptureSuccessAndAssert()
 
-        analyzerFrameAvailableMonitor?.awaitAvailableFramesAndAssert()
+        imageAnalysis?.let {
+            val analyzerFrameAvailableMonitor = ImageAnalysisImageAvailableMonitor()
+            it.setAnalyzer(
+                Executors.newSingleThreadExecutor(),
+                analyzerFrameAvailableMonitor.createAnalyzer()
+            )
+
+            // Assert: checks that images can be received by the ImageAnalysis.Analyzer
+            analyzerFrameAvailableMonitor.awaitAvailableFramesAndAssert()
+        }
     }
 
     private class PreviewFrameAvailableMonitor {
@@ -290,9 +327,11 @@
                 }
 
                 previewFrameCountDownLatch?.let {
-                    it.countDown()
-                    if (it.count == 0L) {
-                        complete = true
+                    if (!complete) {
+                        it.countDown()
+                        if (it.count == 0L) {
+                            complete = true
+                        }
                     }
                 }
             }
@@ -310,7 +349,10 @@
                     surfaceTexture: SurfaceTexture,
                     resolution: Size
                 ) {
-                    surfaceTexture.attachToGLContext(GLUtil.getTexIdFromGLContext())
+                    if (texId == INVALID_TEX_ID) {
+                        texId = GLUtil.getTexIdFromGLContext()
+                    }
+                    surfaceTexture.attachToGLContext(texId)
                     surfaceTexture.setOnFrameAvailableListener(
                         onFrameAvailableListener,
                         frameAvailableHandler
@@ -322,6 +364,7 @@
                 override fun onSafeToRelease(surfaceTexture: SurfaceTexture) {
                     synchronized(isSurfaceTextureReleasedLock) {
                         isSurfaceTextureReleased = true
+                        surfaceTexture.detachFromGLContext()
                         surfaceTexture.release()
                         frameAvailableHandlerThread.quitSafely()
                     }
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCameraStressTest.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCameraStressTest.kt
index 4b72480..5ce56bd 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCameraStressTest.kt
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCameraStressTest.kt
@@ -24,7 +24,7 @@
 import androidx.camera.core.ImageAnalysis
 import androidx.camera.core.ImageCapture
 import androidx.camera.core.Preview
-import androidx.camera.extensions.ExtensionMode
+import androidx.camera.core.UseCase
 import androidx.camera.extensions.ExtensionsManager
 import androidx.camera.integration.extensions.util.ExtensionsTestUtil
 import androidx.camera.integration.extensions.util.ExtensionsTestUtil.STRESS_TEST_OPERATION_REPEAT_COUNT
@@ -82,15 +82,11 @@
     private lateinit var extensionCameraSelector: CameraSelector
     private lateinit var preview: Preview
     private lateinit var imageCapture: ImageCapture
-    private lateinit var imageAnalysis: ImageAnalysis
-    private var isImageAnalysisSupported = false
     private lateinit var lifecycleOwner: FakeLifecycleOwner
 
     @Before
     fun setUp(): Unit = runBlocking {
-        if (extensionMode != ExtensionMode.NONE) {
-            assumeTrue(ExtensionsTestUtil.isTargetDeviceAvailableForExtensions())
-        }
+        assumeTrue(ExtensionsTestUtil.isTargetDeviceAvailableForExtensions())
         cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
         extensionsManager = ExtensionsManager.getInstanceAsync(
             context,
@@ -116,10 +112,6 @@
             preview.setSurfaceProvider(SurfaceTextureProvider.createSurfaceTextureProvider())
         }
         imageCapture = ImageCapture.Builder().build()
-        imageAnalysis = ImageAnalysis.Builder().build()
-
-        isImageAnalysisSupported =
-            camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis)
     }
 
     @After
@@ -140,14 +132,34 @@
         @JvmStatic
         @get:Parameterized.Parameters(name = "cameraId = {0}, extensionMode = {1}")
         val parameters: Collection<Array<Any>>
-            get() = ExtensionsTestUtil.getAllCameraIdModeCombinations()
+            get() = ExtensionsTestUtil.getAllCameraIdExtensionModeCombinations()
     }
 
     @LabTestRule.LabTestOnly
     @Test
     @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
-    fun openCloseCameraStressTest(): Unit = runBlocking {
-        for (i in 1..STRESS_TEST_OPERATION_REPEAT_COUNT) {
+    fun openCloseCameraStressTest_withPreviewImageCapture(): Unit = runBlocking {
+        bindUseCase_unbindAll_toCheckCameraState_repeatedly(preview, imageCapture)
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCameraStressTest_withPreviewImageCaptureImageAnalysis(): Unit = runBlocking {
+        val imageAnalysis = ImageAnalysis.Builder().build()
+        assumeTrue(camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis))
+        bindUseCase_unbindAll_toCheckCameraState_repeatedly(preview, imageCapture, imageAnalysis)
+    }
+
+    /**
+     * Repeatedly binds use cases, unbind all to check whether the camera can be opened and closed
+     * successfully by monitoring the camera state events.
+     */
+    private fun bindUseCase_unbindAll_toCheckCameraState_repeatedly(
+        vararg useCases: UseCase,
+        repeatCount: Int = STRESS_TEST_OPERATION_REPEAT_COUNT
+    ): Unit = runBlocking {
+        for (i in 1..repeatCount) {
             val openCameraLatch = CountDownLatch(1)
             val closeCameraLatch = CountDownLatch(1)
             val observer = Observer<CameraState> { state ->
@@ -159,34 +171,29 @@
             }
 
             withContext(Dispatchers.Main) {
+                // Arrange: sets up CameraState observer
                 camera.cameraInfo.cameraState.observe(lifecycleOwner, observer)
 
-                if (isImageAnalysisSupported) {
-                    cameraProvider.bindToLifecycle(
-                        lifecycleOwner,
-                        extensionCameraSelector,
-                        preview,
-                        imageCapture,
-                        imageAnalysis
-                    )
-                } else {
-                    cameraProvider.bindToLifecycle(
-                        lifecycleOwner,
-                        extensionCameraSelector,
-                        preview,
-                        imageCapture
-                    )
-                }
+                // Act: binds use cases
+                cameraProvider.bindToLifecycle(
+                    lifecycleOwner,
+                    extensionCameraSelector,
+                    *useCases
+                )
             }
 
+            // Assert: checks the CameraState.Type.OPEN can be received
             assertThat(openCameraLatch.await(3000, TimeUnit.MILLISECONDS)).isTrue()
 
+            // Act: unbinds all use cases
             withContext(Dispatchers.Main) {
                 cameraProvider.unbindAll()
             }
 
+            // Assert: checks the CameraState.Type.CLOSED can be received
             assertThat(closeCameraLatch.await(3000, TimeUnit.MILLISECONDS)).isTrue()
 
+            // Clean it up.
             withContext(Dispatchers.Main) {
                 camera.cameraInfo.cameraState.removeObserver(observer)
             }
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCaptureSessionStressTest.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCaptureSessionStressTest.kt
index 55f24d7..a0c0064 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCaptureSessionStressTest.kt
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCaptureSessionStressTest.kt
@@ -29,8 +29,8 @@
 import androidx.camera.core.ImageAnalysis
 import androidx.camera.core.ImageCapture
 import androidx.camera.core.Preview
+import androidx.camera.core.UseCase
 import androidx.camera.core.impl.CameraConfig
-import androidx.camera.core.impl.CameraConfigs
 import androidx.camera.core.impl.CaptureConfig
 import androidx.camera.core.impl.Config
 import androidx.camera.core.impl.ExtendedCameraConfigProviderStore
@@ -102,9 +102,7 @@
 
     @Before
     fun setUp(): Unit = runBlocking {
-        if (extensionMode != ExtensionMode.NONE) {
-            assumeTrue(ExtensionsTestUtil.isTargetDeviceAvailableForExtensions())
-        }
+        assumeTrue(ExtensionsTestUtil.isTargetDeviceAvailableForExtensions())
         cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
         extensionsManager = ExtensionsManager.getInstanceAsync(
             context,
@@ -153,12 +151,39 @@
     @LabTestRule.LabTestOnly
     @Test
     @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
-    fun openCloseCaptureSessionStressTest(): Unit = runBlocking {
-        for (i in 1..STRESS_TEST_OPERATION_REPEAT_COUNT) {
+    fun openCloseCaptureSessionStressTest_withPreviewImageCapture(): Unit = runBlocking {
+        bindUseCase_unbindAll_toCheckCameraEvent_repeatedly(preview, imageCapture)
+    }
+
+    @LabTestRule.LabTestOnly
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCaptureSessionStressTest_withPreviewImageCaptureImageAnalysis(): Unit =
+        runBlocking {
+            val imageAnalysis = ImageAnalysis.Builder().build()
+            assumeTrue(camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis))
+            bindUseCase_unbindAll_toCheckCameraEvent_repeatedly(
+                preview,
+                imageCapture,
+                imageAnalysis
+            )
+        }
+
+    /**
+     * Repeatedly binds use cases, unbind all to check whether the capture session can be opened
+     * and closed successfully by monitoring the CameraEvent callbacks.
+     */
+    private fun bindUseCase_unbindAll_toCheckCameraEvent_repeatedly(
+        vararg useCases: UseCase,
+        repeatCount: Int = STRESS_TEST_OPERATION_REPEAT_COUNT
+    ): Unit = runBlocking {
+        for (i in 1..repeatCount) {
+            // Arrange: resets the camera event monitor
             cameraEventMonitor.reset()
 
             withContext(Dispatchers.Main) {
-                // Retrieves the camera selector which allows to monitor camera event callbacks
+                // Arrange: retrieves the camera selector which allows to monitor camera event
+                // callbacks
                 val extensionEnabledCameraEventMonitorCameraSelector =
                     getExtensionsCameraEventMonitorCameraSelector(
                         extensionsManager,
@@ -166,30 +191,23 @@
                         baseCameraSelector
                     )
 
-                if (isImageAnalysisSupported) {
-                    cameraProvider.bindToLifecycle(
-                        lifecycleOwner,
-                        extensionEnabledCameraEventMonitorCameraSelector,
-                        preview,
-                        imageCapture,
-                        imageAnalysis
-                    )
-                } else {
-                    cameraProvider.bindToLifecycle(
-                        lifecycleOwner,
-                        extensionEnabledCameraEventMonitorCameraSelector,
-                        preview,
-                        imageCapture
-                    )
-                }
+                // Act: binds use cases
+                cameraProvider.bindToLifecycle(
+                    lifecycleOwner,
+                    extensionEnabledCameraEventMonitorCameraSelector,
+                    *useCases
+                )
             }
 
+            // Assert: checks the CameraEvent#onEnableSession callback function is called
             cameraEventMonitor.awaitSessionEnabledAndAssert()
 
+            // Act: unbinds all use cases
             withContext(Dispatchers.Main) {
                 cameraProvider.unbindAll()
             }
 
+            // Assert: checks the CameraEvent#onSessionDisabled callback function is called
             cameraEventMonitor.awaitSessionDisabledAndAssert()
         }
     }
@@ -198,7 +216,7 @@
         @JvmStatic
         @get:Parameterized.Parameters(name = "cameraId = {0}, extensionMode = {1}")
         val parameters: Collection<Array<Any>>
-            get() = ExtensionsTestUtil.getAllCameraIdModeCombinations()
+            get() = ExtensionsTestUtil.getAllCameraIdExtensionModeCombinations()
 
         /**
          * Retrieves the default extended camera config provider id string
@@ -210,7 +228,6 @@
                 ExtensionMode.NIGHT -> "EXTENSION_MODE_NIGHT"
                 ExtensionMode.FACE_RETOUCH -> "EXTENSION_MODE_FACE_RETOUCH"
                 ExtensionMode.AUTO -> "EXTENSION_MODE_AUTO"
-                ExtensionMode.NONE -> "EXTENSION_MODE_NONE"
                 else -> throw IllegalArgumentException("Invalid extension mode!")
             }.let {
                 return ":camera:camera-extensions-$it"
@@ -268,17 +285,9 @@
         val cameraEventConfigProviderId =
             Identifier.create(getCameraEventMonitorCameraConfigProviderId(extensionMode))
 
-        if (extensionMode != ExtensionMode.NONE) {
-            // Calls the ExtensionsManager#getExtensionEnabledCameraSelector() function to add the
-            // default extended camera config provider to ExtendedCameraConfigProviderStore
-            extensionsManager.getExtensionEnabledCameraSelector(baseCameraSelector, extensionMode)
-        } else {
-            // Inserts an empty camera config for normal mode so that the camera event monitor
-            // can be attached by the same flow.
-            ExtendedCameraConfigProviderStore.addConfig(defaultConfigProviderId) {
-                    _, _ -> CameraConfigs.emptyConfig()
-            }
-        }
+        // Calls the ExtensionsManager#getExtensionEnabledCameraSelector() function to add the
+        // default extended camera config provider to ExtendedCameraConfigProviderStore
+        extensionsManager.getExtensionEnabledCameraSelector(baseCameraSelector, extensionMode)
 
         // Injects the new camera config provider which will keep the original extensions needed
         // configs and also add additional CameraEventMonitor to monitor the camera event callbacks.
@@ -364,7 +373,8 @@
         ): Config {
             // Retrieves the config from the default ExtensionsUseCaseConfigFactory
             val mutableOptionsBundle = useCaseConfigFactory?.getConfig(
-                captureType, captureMode)?.let {
+                captureType, captureMode
+            )?.let {
                 MutableOptionsBundle.from(it)
             } ?: MutableOptionsBundle.create()
 
diff --git a/car/app/OWNERS b/car/app/OWNERS
index 040e49d..7cdc4ee 100644
--- a/car/app/OWNERS
+++ b/car/app/OWNERS
@@ -9,3 +9,4 @@
 per-file app-testing/api/*=file:/car/app/API_OWNERS
 
 # Feature owners
+per-file app/*[email protected]
diff --git a/car/app/app-samples/helloworld/common/src/main/java/androidx/car/app/sample/helloworld/common/HelloWorldService.java b/car/app/app-samples/helloworld/common/src/main/java/androidx/car/app/sample/helloworld/common/HelloWorldService.java
index a5e4e2c..f526dfa 100644
--- a/car/app/app-samples/helloworld/common/src/main/java/androidx/car/app/sample/helloworld/common/HelloWorldService.java
+++ b/car/app/app-samples/helloworld/common/src/main/java/androidx/car/app/sample/helloworld/common/HelloWorldService.java
@@ -23,6 +23,7 @@
 import androidx.car.app.CarAppService;
 import androidx.car.app.Screen;
 import androidx.car.app.Session;
+import androidx.car.app.SessionInfo;
 import androidx.car.app.validation.HostValidator;
 
 /**
@@ -38,9 +39,16 @@
         // Exported services must have an empty public constructor.
     }
 
+    @NonNull
+    @Override
+    @SuppressWarnings("deprecation")
+    public Session onCreateSession() {
+        return onCreateSession(SessionInfo.DEFAULT_SESSION_INFO);
+    }
+
     @Override
     @NonNull
-    public Session onCreateSession() {
+    public Session onCreateSession(@NonNull SessionInfo sessionInfo) {
         return new Session() {
             @Override
             @NonNull
diff --git a/car/app/app-samples/navigation/common/src/main/AndroidManifest.xml b/car/app/app-samples/navigation/common/src/main/AndroidManifest.xml
index fff984f..0786374 100644
--- a/car/app/app-samples/navigation/common/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/navigation/common/src/main/AndroidManifest.xml
@@ -14,8 +14,7 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -->
-<manifest package="androidx.car.app.sample.navigation.common"
-    xmlns:android="http://schemas.android.com/apk/res/android">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/car/app/app-samples/places/common/src/main/java/androidx/car/app/sample/places/common/PlacesCarAppService.java b/car/app/app-samples/places/common/src/main/java/androidx/car/app/sample/places/common/PlacesCarAppService.java
index 044338a..edc0e11 100644
--- a/car/app/app-samples/places/common/src/main/java/androidx/car/app/sample/places/common/PlacesCarAppService.java
+++ b/car/app/app-samples/places/common/src/main/java/androidx/car/app/sample/places/common/PlacesCarAppService.java
@@ -26,6 +26,7 @@
 import androidx.car.app.Screen;
 import androidx.car.app.ScreenManager;
 import androidx.car.app.Session;
+import androidx.car.app.SessionInfo;
 import androidx.car.app.validation.HostValidator;
 
 /**
@@ -36,9 +37,16 @@
  * Cars Library developer guide</a>.
  */
 public class PlacesCarAppService extends CarAppService {
+    @NonNull
+    @Override
+    @SuppressWarnings("deprecation")
+    public Session onCreateSession() {
+        return onCreateSession(SessionInfo.DEFAULT_SESSION_INFO);
+    }
+
     @Override
     @NonNull
-    public Session onCreateSession() {
+    public Session onCreateSession(@NonNull SessionInfo sessionInfo) {
         return new Session() {
             @Override
             @NonNull
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/ShowcaseService.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/ShowcaseService.java
index 3468b23..78fbc77 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/ShowcaseService.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/ShowcaseService.java
@@ -22,6 +22,7 @@
 import androidx.annotation.NonNull;
 import androidx.car.app.CarAppService;
 import androidx.car.app.Session;
+import androidx.car.app.SessionInfo;
 import androidx.car.app.validation.HostValidator;
 
 /**
@@ -51,7 +52,14 @@
 
     @Override
     @NonNull
+    @SuppressWarnings("deprecation")
     public Session onCreateSession() {
+        return onCreateSession(SessionInfo.DEFAULT_SESSION_INFO);
+    }
+
+    @NonNull
+    @Override
+    public Session onCreateSession(@NonNull SessionInfo sessionInfo) {
         return new ShowcaseSession();
     }
 
diff --git a/car/app/app-testing/lint-baseline.xml b/car/app/app-testing/lint-baseline.xml
index b0f5029..a43e379 100644
--- a/car/app/app-testing/lint-baseline.xml
+++ b/car/app/app-testing/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/car/app/app/api/current.txt b/car/app/app/api/current.txt
index 7c1aaca..4a9180c 100644
--- a/car/app/app/api/current.txt
+++ b/car/app/app/api/current.txt
@@ -32,7 +32,8 @@
     method public final androidx.car.app.Session? getCurrentSession();
     method public final androidx.car.app.HostInfo? getHostInfo();
     method @CallSuper public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract androidx.car.app.Session onCreateSession();
+    method @Deprecated public abstract androidx.car.app.Session onCreateSession();
+    method public androidx.car.app.Session onCreateSession(androidx.car.app.SessionInfo);
     method public final boolean onUnbind(android.content.Intent);
     field @Deprecated public static final String CATEGORY_CHARGING_APP = "androidx.car.app.category.CHARGING";
     field public static final String CATEGORY_NAVIGATION_APP = "androidx.car.app.category.NAVIGATION";
@@ -158,6 +159,7 @@
     ctor public SessionInfo(int, String);
     method public int getDisplayType();
     method public String getSessionId();
+    field public static final androidx.car.app.SessionInfo DEFAULT_SESSION_INFO;
     field public static final int DISPLAY_TYPE_CLUSTER = 1; // 0x1
     field public static final int DISPLAY_TYPE_MAIN = 0; // 0x0
   }
diff --git a/car/app/app/api/public_plus_experimental_current.txt b/car/app/app/api/public_plus_experimental_current.txt
index 5c54e77..6c3092f 100644
--- a/car/app/app/api/public_plus_experimental_current.txt
+++ b/car/app/app/api/public_plus_experimental_current.txt
@@ -32,7 +32,8 @@
     method public final androidx.car.app.Session? getCurrentSession();
     method public final androidx.car.app.HostInfo? getHostInfo();
     method @CallSuper public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract androidx.car.app.Session onCreateSession();
+    method @Deprecated public abstract androidx.car.app.Session onCreateSession();
+    method public androidx.car.app.Session onCreateSession(androidx.car.app.SessionInfo);
     method public final boolean onUnbind(android.content.Intent);
     field @Deprecated public static final String CATEGORY_CHARGING_APP = "androidx.car.app.category.CHARGING";
     field public static final String CATEGORY_NAVIGATION_APP = "androidx.car.app.category.NAVIGATION";
@@ -160,6 +161,7 @@
     method public int getDisplayType();
     method public String getSessionId();
     method @androidx.car.app.annotations.ExperimentalCarApi public java.util.Set<java.lang.Class<? extends androidx.car.app.model.Template>!>? getSupportedTemplates(int);
+    field public static final androidx.car.app.SessionInfo DEFAULT_SESSION_INFO;
     field public static final int DISPLAY_TYPE_CLUSTER = 1; // 0x1
     field public static final int DISPLAY_TYPE_MAIN = 0; // 0x0
   }
diff --git a/car/app/app/api/restricted_current.txt b/car/app/app/api/restricted_current.txt
index 7c1aaca..4a9180c 100644
--- a/car/app/app/api/restricted_current.txt
+++ b/car/app/app/api/restricted_current.txt
@@ -32,7 +32,8 @@
     method public final androidx.car.app.Session? getCurrentSession();
     method public final androidx.car.app.HostInfo? getHostInfo();
     method @CallSuper public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract androidx.car.app.Session onCreateSession();
+    method @Deprecated public abstract androidx.car.app.Session onCreateSession();
+    method public androidx.car.app.Session onCreateSession(androidx.car.app.SessionInfo);
     method public final boolean onUnbind(android.content.Intent);
     field @Deprecated public static final String CATEGORY_CHARGING_APP = "androidx.car.app.category.CHARGING";
     field public static final String CATEGORY_NAVIGATION_APP = "androidx.car.app.category.NAVIGATION";
@@ -158,6 +159,7 @@
     ctor public SessionInfo(int, String);
     method public int getDisplayType();
     method public String getSessionId();
+    field public static final androidx.car.app.SessionInfo DEFAULT_SESSION_INFO;
     field public static final int DISPLAY_TYPE_CLUSTER = 1; // 0x1
     field public static final int DISPLAY_TYPE_MAIN = 0; // 0x0
   }
diff --git a/car/app/app/lint-baseline.xml b/car/app/app/lint-baseline.xml
index c803e93..fc546b9 100644
--- a/car/app/app/lint-baseline.xml
+++ b/car/app/app/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
@@ -372,7 +372,7 @@
 
     <issue
         id="NullabilityAnnotationsDetector"
-        message="Use @androidx.annotation.NonNull instead of @org.jetbrains.annotations.NotNull"
+        message="Use `@androidx.annotation.NonNull` instead of `@org.jetbrains.annotations.NotNull`"
         errorLine1="    public void sendPanModeChanged(boolean isInPanMode, @NonNull @NotNull OnDoneCallback callback) {"
         errorLine2="                                                                 ~~~~~~~~">
         <location
diff --git a/car/app/app/src/main/java/androidx/car/app/CarAppBinder.java b/car/app/app/src/main/java/androidx/car/app/CarAppBinder.java
index 9d774e0..31c476a 100644
--- a/car/app/app/src/main/java/androidx/car/app/CarAppBinder.java
+++ b/car/app/app/src/main/java/androidx/car/app/CarAppBinder.java
@@ -44,9 +44,10 @@
 
 /** Implementation of the binder {@link ICarApp}. */
 final class CarAppBinder extends ICarApp.Stub {
+    private final SessionInfo mCurrentSessionInfo;
+
     @Nullable
     private CarAppService mService;
-
     @Nullable
     private Session mCurrentSession;
     @Nullable
@@ -54,8 +55,14 @@
     @Nullable
     private HandshakeInfo mHandshakeInfo;
 
-    CarAppBinder(@NonNull CarAppService service) {
+    /**
+     * Creates a new {@link CarAppBinder} instance for a {@link SessionInfo}. Once the Host
+     * requests {@link #onAppCreate(ICarHost, Intent, Configuration, IOnDoneCallback)}, the
+     * {@link Session} will be created.
+     */
+    CarAppBinder(@NonNull CarAppService service, @NonNull SessionInfo sessionInfo) {
         mService = service;
+        mCurrentSessionInfo = sessionInfo;
     }
 
     /**
@@ -105,7 +112,7 @@
             Session session = mCurrentSession;
             if (session == null
                     || session.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
-                session = service.onCreateSession();
+                session = service.onCreateSession(requireNonNull(mCurrentSessionInfo));
                 mCurrentSession = session;
             }
 
@@ -366,4 +373,10 @@
     Session getCurrentSession() {
         return mCurrentSession;
     }
+
+    @VisibleForTesting
+    @NonNull
+    SessionInfo getCurrentSessionInfo() {
+        return mCurrentSessionInfo;
+    }
 }
diff --git a/car/app/app/src/main/java/androidx/car/app/CarAppService.java b/car/app/app/src/main/java/androidx/car/app/CarAppService.java
index ccd4973..03d3f0c 100644
--- a/car/app/app/src/main/java/androidx/car/app/CarAppService.java
+++ b/car/app/app/src/main/java/androidx/car/app/CarAppService.java
@@ -19,8 +19,6 @@
 import static androidx.car.app.utils.LogTags.TAG;
 import static androidx.car.app.utils.ThreadUtils.runOnMain;
 
-import static java.util.Objects.requireNonNull;
-
 import android.app.Service;
 import android.content.Intent;
 import android.os.IBinder;
@@ -132,12 +130,6 @@
 
     @Override
     @CallSuper
-    public void onCreate() {
-        mBinder = new CarAppBinder(this);
-    }
-
-    @Override
-    @CallSuper
     public void onDestroy() {
         if (mBinder != null) {
             mBinder.destroy();
@@ -157,7 +149,9 @@
     @CallSuper
     @NonNull
     public final IBinder onBind(@NonNull Intent intent) {
-        return requireNonNull(mBinder);
+        CarAppBinder response = new CarAppBinder(this, SessionInfo.DEFAULT_SESSION_INFO);
+        mBinder = response;
+        return response;
     }
 
     /**
@@ -234,10 +228,35 @@
      * <p>Called by the system, do not call this method directly.
      *
      * @see CarContext#startCarApp(Intent)
+     * @deprecated this method continues to exist for backwards compatibility; however, is
+     * succeeded by {@link #onCreateSession(SessionInfo)}. Prefer to implement {@link
+     * #onCreateSession(SessionInfo)} and use {@link SessionInfo#DEFAULT_SESSION_INFO} to forward
+     * this method to the new one.
      */
     @NonNull
+    @Deprecated
     public abstract Session onCreateSession();
 
+
+    // TODO(b/236140507): Link AndroidManifest.xml documentation or equivalent in this javadoc
+    /**
+     * Creates a new {@link Session}.
+     *
+     * <p>This method is invoked once per app-supported physical display with a unique
+     * {@link SessionInfo} identifying the type of display. Support for displays is declared within
+     * the AndroidManifest.xml. This method can also be invoked if the previous instance has been
+     * destroyed (ie. due to memory pressure) and the system has not yet destroyed this service.
+     *
+     * <p>This method is called by the system and should not be called directly.
+     *
+     * @see CarContext#startCarApp(Intent)
+     */
+    @NonNull
+    @SuppressWarnings("deprecation")
+    public Session onCreateSession(@NonNull SessionInfo sessionInfo) {
+        return onCreateSession();
+    }
+
     @Override
     @CallSuper
     public final void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
diff --git a/car/app/app/src/main/java/androidx/car/app/SessionInfo.java b/car/app/app/src/main/java/androidx/car/app/SessionInfo.java
index 523e2ea..3176923 100644
--- a/car/app/app/src/main/java/androidx/car/app/SessionInfo.java
+++ b/car/app/app/src/main/java/androidx/car/app/SessionInfo.java
@@ -15,15 +15,12 @@
  */
 package androidx.car.app;
 
-import static androidx.annotation.RestrictTo.Scope.LIBRARY;
-
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.Keep;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
 import androidx.car.app.annotations.CarProtocol;
 import androidx.car.app.annotations.ExperimentalCarApi;
 import androidx.car.app.annotations.RequiresCarApi;
@@ -35,12 +32,15 @@
 import com.google.common.collect.ImmutableSet;
 
 import java.lang.annotation.Retention;
+import java.util.Objects;
 import java.util.Set;
 
 /** Information about a {@link Session}, such as the physical display and the session ID. */
 @RequiresCarApi(5)
 @CarProtocol
 public class SessionInfo {
+    private static final char DIVIDER = '/';
+
     /** The primary infotainment display usually in the center column of the vehicle. */
     public static final int DISPLAY_TYPE_MAIN = 0;
 
@@ -63,11 +63,9 @@
     /**
      * A default {@link SessionInfo} for the main display, used when the host is on a version
      * that doesn't support this new class.
-     *
-     * @hide
      */
-    @RestrictTo(LIBRARY)
-    static final SessionInfo DEFAULT_SESSION_INFO = new SessionInfo(
+    @NonNull
+    public static final SessionInfo DEFAULT_SESSION_INFO = new SessionInfo(
             DISPLAY_TYPE_MAIN, "main");
 
     /** A string identifier unique per physical display. */
@@ -128,4 +126,31 @@
 
         return null;
     }
+
+    @NonNull
+    @Override
+    public String toString() {
+        return String.valueOf(mDisplayType) + DIVIDER + mSessionId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSessionId, mDisplayType);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof SessionInfo)) {
+            return false;
+        }
+        if (obj == this) {
+            return true;
+        }
+        SessionInfo object = (SessionInfo) obj;
+        return this.getSessionId().equals(object.getSessionId())
+                && this.getDisplayType() == object.getDisplayType();
+    }
 }
diff --git a/car/app/app/src/test/java/androidx/car/app/CarAppBinderTest.java b/car/app/app/src/test/java/androidx/car/app/CarAppBinderTest.java
index 7664c96..63c5c9c 100644
--- a/car/app/app/src/test/java/androidx/car/app/CarAppBinderTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/CarAppBinderTest.java
@@ -24,14 +24,17 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.annotation.SuppressLint;
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.RemoteException;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.car.app.model.ItemList;
 import androidx.car.app.model.PlaceListMapTemplate;
 import androidx.car.app.model.Template;
@@ -48,6 +51,7 @@
 import androidx.test.core.app.ApplicationProvider;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -55,6 +59,8 @@
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.internal.DoNotInstrument;
 
@@ -65,56 +71,36 @@
 @RunWith(RobolectricTestRunner.class)
 @DoNotInstrument
 public class CarAppBinderTest {
-    @Mock
-    ICarHost mMockCarHost;
-    @Mock
-    DefaultLifecycleObserver mLifecycleObserver;
-    @Mock
-    IOnDoneCallback mMockOnDoneCallback;
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
 
-    private TestCarContext mCarContext;
-    private final Template mTemplate =
-            new PlaceListMapTemplate.Builder()
-                    .setTitle("Title")
-                    .setItemList(new ItemList.Builder().build())
-                    .build();
+    private static final Template TEST_TEMPLATE = new PlaceListMapTemplate.Builder().setTitle(
+            "Title").setItemList(new ItemList.Builder().build()).build();
+
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+
+    @Mock
+    private ICarHost mMockCarHost;
+    @Mock
+    private DefaultLifecycleObserver mLifecycleObserver;
+    @Mock
+    private IOnDoneCallback mMockOnDoneCallback;
     @Captor
-    ArgumentCaptor<Bundleable> mBundleableArgumentCaptor;
+    private ArgumentCaptor<Bundleable> mBundleableArgumentCaptor;
 
-    private CarAppService mCarAppService;
+    private TestCarAppService mCarAppService;
     private CarAppBinder mCarAppBinder;
-    private SessionController mSessionController;
     private Intent mIntentSet;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mCarAppService =
-                new CarAppService() {
-                    @Override
-                    @NonNull
-                    public HostValidator createHostValidator() {
-                        return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR;
-                    }
-
-                    @Override
-                    @NonNull
-                    public Session onCreateSession() {
-                        // Recreate a new CarContext, because the previous one would have been
-                        // destroyed in an unbind-rebind scenario.
-                        mCarContext = TestCarContext.createCarContext(
-                                ApplicationProvider.getApplicationContext());
-                        Session session = createTestSession();
-                        mSessionController = new SessionController(session, mCarContext,
-                                new Intent());
-                        return session;
-                    }
-                };
+        mCarAppService = new TestCarAppService();
 
         AppInfo appInfo = new AppInfo(CarAppApiLevels.getOldest(), CarAppApiLevels.getLatest(),
                 "blah");
         mCarAppService.setAppInfo(appInfo);
-        mCarAppBinder = new CarAppBinder(mCarAppService);
+        mCarAppBinder = new CarAppBinder(mCarAppService, SessionInfo.DEFAULT_SESSION_INFO);
         mCarAppService.setCarAppbinder(mCarAppBinder);
 
         // Sets default handshake and host info. OnAppCreate depends on these being non-null.
@@ -137,7 +123,7 @@
                     @Override
                     @NonNull
                     public Template onGetTemplate() {
-                        return mTemplate;
+                        return TEST_TEMPLATE;
                     }
                 };
             }
@@ -150,7 +136,7 @@
     }
 
     @Test
-    public void onAppCreate_updatesCarApiLevel() throws RemoteException, BundlerException {
+    public void onAppCreate_updatesCarApiLevel() throws BundlerException {
         String hostPackageName = "com.google.projection.gearhead";
         int hostApiLevel = CarAppApiLevels.LEVEL_1;
         HandshakeInfo handshakeInfo = new HandshakeInfo(hostPackageName, hostApiLevel);
@@ -158,41 +144,34 @@
         mCarAppBinder.onHandshakeCompleted(Bundleable.create(handshakeInfo), mMockOnDoneCallback);
         mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(), mMockOnDoneCallback);
 
-        assertThat(
-                mCarAppBinder.getCurrentSession().getCarContext().getCarAppApiLevel()).isEqualTo(
+        assertThat(mCarAppBinder.getCurrentSession().getCarContext().getCarAppApiLevel()).isEqualTo(
                 hostApiLevel);
     }
 
     @Test
-    public void onAppCreate_updatesContextHostInfo()
-            throws RemoteException, BundlerException, InterruptedException {
-        String hostPackageName = "com.google.projection.gearhead";
-        HandshakeInfo handshakeInfo = new HandshakeInfo(hostPackageName, CarAppApiLevels.LEVEL_1);
+    public void onAppCreate_updatesContextHostInfo() throws BundlerException {
+        String differentHostPackage = "different.package.name";
+        HandshakeInfo handshakeInfo = new HandshakeInfo(differentHostPackage,
+                CarAppApiLevels.LEVEL_1);
 
         mCarAppBinder.onHandshakeCompleted(Bundleable.create(handshakeInfo), mMockOnDoneCallback);
         mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(), mMockOnDoneCallback);
 
-        assertThat(mCarAppBinder.getCurrentSession()
-                .getCarContext().getHostInfo().getPackageName()).isEqualTo(hostPackageName);
+        assertThat(mCarAppBinder.getCurrentSession().getCarContext().getHostInfo().getPackageName())
+                .isEqualTo(differentHostPackage);
     }
 
     @Test
-    public void onAppCreate_createsFirstScreen() throws RemoteException {
+    public void onAppCreate_createsFirstScreen() {
         mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(), mMockOnDoneCallback);
 
-        assertThat(
-                mCarAppBinder
-                        .getCurrentSession()
-                        .getCarContext()
-                        .getCarService(ScreenManager.class)
-                        .getTopTemplate()
-                        .getTemplate())
-                .isInstanceOf(PlaceListMapTemplate.class);
+        assertThat(mCarAppBinder.getCurrentSession().getCarContext().getCarService(
+                ScreenManager.class).getTopTemplate().getTemplate()).isInstanceOf(
+                PlaceListMapTemplate.class);
     }
 
     @Test
-    public void onAppCreate_withIntent_callsWithOnCreateScreenWithIntent() throws
-            RemoteException {
+    public void onAppCreate_withIntent_callsWithOnCreateScreenWithIntent() throws RemoteException {
         Intent intent = new Intent("Foo");
         mCarAppBinder.onAppCreate(mMockCarHost, intent, new Configuration(), mMockOnDoneCallback);
 
@@ -218,28 +197,27 @@
 
     @SuppressLint("NewApi")
     @Test
-    public void onAppCreate_updatesTheConfiguration() throws RemoteException {
+    public void onAppCreate_updatesTheConfiguration() {
         Configuration configuration = new Configuration();
         configuration.setToDefaults();
         configuration.setLocale(Locale.CANADA_FRENCH);
 
-        mCarAppBinder.onAppCreate(mMockCarHost, null, configuration, mock(IOnDoneCallback.class));
+        mCarAppBinder.onAppCreate(mMockCarHost, null, configuration, mMockOnDoneCallback);
 
-        assertThat(mCarContext.getResources().getConfiguration().getLocales().get(0))
-                .isEqualTo(Locale.CANADA_FRENCH);
+        assertThat(mCarAppService.mCarContext.getResources().getConfiguration().getLocales().get(
+                0)).isEqualTo(Locale.CANADA_FRENCH);
     }
 
     @Test
     public void onNewIntent_callsOnNewIntentWithIntent() throws RemoteException {
         Intent intent = new Intent("Foo");
-        mCarAppBinder.onAppCreate(mMockCarHost, intent, new Configuration(),
-                mock(IOnDoneCallback.class));
+        mCarAppBinder.onAppCreate(mMockCarHost, intent, new Configuration(), mMockOnDoneCallback);
 
         Intent intent2 = new Intent("Foo2");
         mCarAppBinder.onNewIntent(intent2, mMockOnDoneCallback);
 
         assertThat(mIntentSet).isEqualTo(intent2);
-        verify(mMockOnDoneCallback).onSuccess(any());
+        verify(mMockOnDoneCallback, times(2)).onSuccess(any());
     }
 
     @Test
@@ -252,9 +230,8 @@
     }
 
     @Test
-    public void getNavigationManager() throws RemoteException {
-        mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(),
-                mock(IOnDoneCallback.class));
+    public void getNavigationManager() {
+        mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(), mMockOnDoneCallback);
 
         assertThat(mCarAppBinder.getCurrentSession().getCarContext().getCarService(
                 NavigationManager.class)).isNotNull();
@@ -269,7 +246,6 @@
 
         mCarAppBinder.onConfigurationChanged(configuration, mMockOnDoneCallback);
 
-        assertThat(mCarContext).isNull();
         verify(mMockOnDoneCallback).onFailure(any());
     }
 
@@ -285,8 +261,8 @@
 
         mCarAppBinder.onConfigurationChanged(configuration, mMockOnDoneCallback);
 
-        assertThat(mCarContext.getResources().getConfiguration().getLocales().get(0))
-                .isEqualTo(Locale.CANADA_FRENCH);
+        assertThat(mCarAppService.mCarContext.getResources().getConfiguration().getLocales().get(
+                0)).isEqualTo(Locale.CANADA_FRENCH);
         verify(mMockOnDoneCallback).onSuccess(any());
     }
 
@@ -299,17 +275,16 @@
 
         verify(mMockOnDoneCallback).onSuccess(mBundleableArgumentCaptor.capture());
         AppInfo receivedAppInfo = (AppInfo) mBundleableArgumentCaptor.getValue().get();
-        assertThat(receivedAppInfo.getMinCarAppApiLevel())
-                .isEqualTo(appInfo.getMinCarAppApiLevel());
-        assertThat(receivedAppInfo.getLatestCarAppApiLevel())
-                .isEqualTo(appInfo.getLatestCarAppApiLevel());
+        assertThat(receivedAppInfo.getMinCarAppApiLevel()).isEqualTo(
+                appInfo.getMinCarAppApiLevel());
+        assertThat(receivedAppInfo.getLatestCarAppApiLevel()).isEqualTo(
+                appInfo.getLatestCarAppApiLevel());
         assertThat(receivedAppInfo.getLibraryDisplayVersion()).isEqualTo(
                 appInfo.getLibraryDisplayVersion());
     }
 
     @Test
-    public void onHandshakeCompleted_updatesHostInfo()
-            throws RemoteException, BundlerException, InterruptedException {
+    public void onHandshakeCompleted_updatesHostInfo() throws BundlerException {
         String hostPackageName = "com.google.projection.gearhead";
         HandshakeInfo handshakeInfo = new HandshakeInfo(hostPackageName, CarAppApiLevels.LEVEL_1);
 
@@ -320,8 +295,7 @@
     }
 
     @Test
-    public void onHandshakeCompleted_updatesHandshakeInfo() throws RemoteException,
-            BundlerException {
+    public void onHandshakeCompleted_updatesHandshakeInfo() throws BundlerException {
         String hostPackageName = "com.google.projection.gearhead";
 
         HandshakeInfo handshakeInfo = new HandshakeInfo(hostPackageName, CarAppApiLevels.LEVEL_1);
@@ -334,21 +308,20 @@
     }
 
     @Test
-    public void onHandshakeCompleted_lowerThanMinApiLevel_throws() throws BundlerException,
-            RemoteException {
+    public void onHandshakeCompleted_lowerThanMinApiLevel_throws()
+            throws BundlerException, RemoteException {
         AppInfo appInfo = new AppInfo(3, 4, "foo");
         mCarAppService.setAppInfo(appInfo);
 
-        HandshakeInfo handshakeInfo = new HandshakeInfo("bar",
-                appInfo.getMinCarAppApiLevel() - 1);
+        HandshakeInfo handshakeInfo = new HandshakeInfo("bar", appInfo.getMinCarAppApiLevel() - 1);
         mCarAppBinder.onHandshakeCompleted(Bundleable.create(handshakeInfo), mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onFailure(any());
     }
 
     @Test
-    public void onHandshakeCompleted_higherThanCurrentApiLevel_throws() throws BundlerException,
-            RemoteException {
+    public void onHandshakeCompleted_higherThanCurrentApiLevel_throws()
+            throws BundlerException, RemoteException {
         AppInfo appInfo = new AppInfo(3, 4, "foo");
         mCarAppService.setAppInfo(appInfo);
 
@@ -360,7 +333,7 @@
     }
 
     @Test
-    public void destroy_movesLifecycleStateToDestroyed() throws RemoteException {
+    public void destroy_movesLifecycleStateToDestroyed() {
         mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(), mMockOnDoneCallback);
         mCarAppBinder.onAppStart(mMockOnDoneCallback);
 
@@ -374,8 +347,7 @@
     }
 
     @Test
-    public void onDestroyLifecycle_onCreate_callsOnCreateScreen() throws RemoteException,
-            BundlerException {
+    public void onDestroyLifecycle_onCreate_callsOnCreateScreen() throws BundlerException {
         mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(), mMockOnDoneCallback);
         mCarAppBinder.onAppStart(mMockOnDoneCallback);
 
@@ -403,12 +375,11 @@
     }
 
     @Test
-    public void onDestroyLifecycle_clearsScreenStack() throws RemoteException {
+    public void onDestroyLifecycle_clearsScreenStack() {
         mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(), mMockOnDoneCallback);
 
-        Deque<Screen> screenStack =
-                mCarAppBinder.getCurrentSession().getCarContext().getCarService(
-                        ScreenManager.class).getScreenStack();
+        Deque<Screen> screenStack = mCarAppBinder.getCurrentSession().getCarContext().getCarService(
+                ScreenManager.class).getScreenStack();
         assertThat(screenStack).hasSize(1);
 
         Screen screen = screenStack.getFirst();
@@ -421,8 +392,7 @@
     }
 
     @Test
-    public void onNewIntent_callsSessionIntent() throws
-            RemoteException {
+    public void onNewIntent_callsSessionIntent() throws RemoteException {
         // onAppCreate must be called first to create the Session before onNewIntent.
         mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(),
                 mock(IOnDoneCallback.class));
@@ -436,8 +406,8 @@
     }
 
     @Test
-    public void onNewIntent_notAtLeastCreated_doesCallSessionIntent_sendsFailure() throws
-            RemoteException {
+    public void onNewIntent_notAtLeastCreated_doesCallSessionIntent_sendsFailure()
+            throws RemoteException {
         Intent intent = new Intent("Foo");
         mCarAppBinder.onNewIntent(intent, mMockOnDoneCallback);
 
@@ -446,15 +416,15 @@
     }
 
     @Test
-    public void onNewIntent_destroyed_doesCallSessionIntent_sendsFailure() throws
-            RemoteException {
+    public void onNewIntent_destroyed_doesCallSessionIntent_sendsFailure() throws RemoteException {
         // onAppCreate must be called first to create the Session before onNewIntent.
         Intent intent1 = new Intent();
         mCarAppBinder.onAppCreate(mMockCarHost, intent1, new Configuration(),
                 mock(IOnDoneCallback.class));
         assertThat(mIntentSet).isEqualTo(intent1);
 
-        mCarContext.getLifecycleOwner().mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
+        mCarAppService.mCarContext.getLifecycleOwner().mRegistry.handleLifecycleEvent(
+                Lifecycle.Event.ON_DESTROY);
 
         Intent intent2 = new Intent("Foo");
         mCarAppBinder.onNewIntent(intent2, mMockOnDoneCallback);
@@ -471,8 +441,8 @@
         mCarAppBinder.onAppStart(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onSuccess(any());
-        assertThat(mCarContext.getLifecycleOwner().mRegistry.getCurrentState()).isEqualTo(
-                Lifecycle.State.STARTED);
+        assertThat(mCarAppService.mCarContext.getLifecycleOwner().mRegistry.getCurrentState())
+                .isEqualTo(Lifecycle.State.STARTED);
     }
 
     @Test
@@ -481,21 +451,20 @@
         mCarAppBinder.onAppStart(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onFailure(any());
-        assertThat(mCarContext).isNull();
     }
 
     @Test
-    public void onAppStart_destroyed_doesNotMoveLifecycle_sendsFailure()
-            throws RemoteException {
+    public void onAppStart_destroyed_doesNotMoveLifecycle_sendsFailure() throws RemoteException {
         mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(),
                 mock(IOnDoneCallback.class));
-        mCarContext.getLifecycleOwner().mRegistry.setCurrentState(Lifecycle.State.DESTROYED);
+        mCarAppService.mCarContext.getLifecycleOwner().mRegistry.setCurrentState(
+                Lifecycle.State.DESTROYED);
 
         mCarAppBinder.onAppStart(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onFailure(any());
-        assertThat(mCarContext.getLifecycleOwner().mRegistry.getCurrentState()).isEqualTo(
-                Lifecycle.State.DESTROYED);
+        assertThat(mCarAppService.mCarContext.getLifecycleOwner().mRegistry.getCurrentState())
+                .isEqualTo(Lifecycle.State.DESTROYED);
     }
 
     @Test
@@ -506,8 +475,8 @@
         mCarAppBinder.onAppResume(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onSuccess(any());
-        assertThat(mCarContext.getLifecycleOwner().mRegistry.getCurrentState()).isEqualTo(
-                Lifecycle.State.RESUMED);
+        assertThat(mCarAppService.mCarContext.getLifecycleOwner().mRegistry.getCurrentState())
+                .isEqualTo(Lifecycle.State.RESUMED);
     }
 
     @Test
@@ -516,21 +485,20 @@
         mCarAppBinder.onAppResume(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onFailure(any());
-        assertThat(mCarContext).isNull();
     }
 
     @Test
-    public void onAppResume_destroyed_doesNotMoveLifecycle_sendsFailure()
-            throws RemoteException {
+    public void onAppResume_destroyed_doesNotMoveLifecycle_sendsFailure() throws RemoteException {
         mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(),
                 mock(IOnDoneCallback.class));
-        mCarContext.getLifecycleOwner().mRegistry.setCurrentState(Lifecycle.State.DESTROYED);
+        mCarAppService.mCarContext.getLifecycleOwner().mRegistry.setCurrentState(
+                Lifecycle.State.DESTROYED);
 
         mCarAppBinder.onAppResume(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onFailure(any());
-        assertThat(mCarContext.getLifecycleOwner().mRegistry.getCurrentState()).isEqualTo(
-                Lifecycle.State.DESTROYED);
+        assertThat(mCarAppService.mCarContext.getLifecycleOwner().mRegistry.getCurrentState())
+                .isEqualTo(Lifecycle.State.DESTROYED);
     }
 
     @Test
@@ -541,8 +509,8 @@
         mCarAppBinder.onAppPause(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onSuccess(any());
-        assertThat(mCarContext.getLifecycleOwner().mRegistry.getCurrentState()).isEqualTo(
-                Lifecycle.State.STARTED);
+        assertThat(mCarAppService.mCarContext.getLifecycleOwner().mRegistry.getCurrentState())
+                .isEqualTo(Lifecycle.State.STARTED);
     }
 
     @Test
@@ -551,21 +519,20 @@
         mCarAppBinder.onAppPause(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onFailure(any());
-        assertThat(mCarContext).isNull();
     }
 
     @Test
-    public void onAppPause_destroyed_doesNotMoveLifecycle_sendsFailure()
-            throws RemoteException {
+    public void onAppPause_destroyed_doesNotMoveLifecycle_sendsFailure() throws RemoteException {
         mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(),
                 mock(IOnDoneCallback.class));
-        mCarContext.getLifecycleOwner().mRegistry.setCurrentState(Lifecycle.State.DESTROYED);
+        mCarAppService.mCarContext.getLifecycleOwner().mRegistry.setCurrentState(
+                Lifecycle.State.DESTROYED);
 
         mCarAppBinder.onAppPause(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onFailure(any());
-        assertThat(mCarContext.getLifecycleOwner().mRegistry.getCurrentState()).isEqualTo(
-                Lifecycle.State.DESTROYED);
+        assertThat(mCarAppService.mCarContext.getLifecycleOwner().mRegistry.getCurrentState())
+                .isEqualTo(Lifecycle.State.DESTROYED);
     }
 
     @Test
@@ -576,8 +543,8 @@
         mCarAppBinder.onAppStop(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onSuccess(any());
-        assertThat(mCarContext.getLifecycleOwner().mRegistry.getCurrentState()).isEqualTo(
-                Lifecycle.State.CREATED);
+        assertThat(mCarAppService.mCarContext.getLifecycleOwner().mRegistry.getCurrentState())
+                .isEqualTo(Lifecycle.State.CREATED);
     }
 
     @Test
@@ -586,26 +553,24 @@
         mCarAppBinder.onAppStop(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onFailure(any());
-        assertThat(mCarContext).isNull();
     }
 
     @Test
-    public void onAppStop_destroyed_doesNotMoveLifecycle_sendsFailure()
-            throws RemoteException {
+    public void onAppStop_destroyed_doesNotMoveLifecycle_sendsFailure() throws RemoteException {
         mCarAppBinder.onAppCreate(mMockCarHost, null, new Configuration(),
                 mock(IOnDoneCallback.class));
-        mCarContext.getLifecycleOwner().mRegistry.setCurrentState(Lifecycle.State.DESTROYED);
+        mCarAppService.mCarContext.getLifecycleOwner().mRegistry.setCurrentState(
+                Lifecycle.State.DESTROYED);
 
         mCarAppBinder.onAppStop(mMockOnDoneCallback);
 
         verify(mMockOnDoneCallback).onFailure(any());
-        assertThat(mCarContext.getLifecycleOwner().mRegistry.getCurrentState()).isEqualTo(
-                Lifecycle.State.DESTROYED);
+        assertThat(mCarAppService.mCarContext.getLifecycleOwner().mRegistry.getCurrentState())
+                .isEqualTo(Lifecycle.State.DESTROYED);
     }
 
     @Test
-    public void session_screen_lifecycleEvents_inCorrectOrder()
-            throws RemoteException {
+    public void session_screen_lifecycleEvents_inCorrectOrder() throws RemoteException {
         // We have to manually create the Session here instead of rely on using ICarApp because
         // of two issues:
         // 1. If we inject a TestCarContext, it will overwrite a TestLifeCycleOwner instance that
@@ -629,4 +594,42 @@
         inOrder.verify(screenObserver).onDestroy(any());
         inOrder.verify(sessionObserver).onDestroy(any());
     }
+
+    /** An implementation of {@link CarAppService} for testing. */
+    private class TestCarAppService extends CarAppService {
+        @Nullable
+        public SessionController mSessionController;
+        @Nullable
+        public TestCarContext mCarContext;
+        @Nullable
+        public Session mSession;
+        @Nullable
+        public SessionInfo mSessionInfo;
+
+        @Override
+        @NonNull
+        public HostValidator createHostValidator() {
+            return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR;
+        }
+
+        @NonNull
+        @Override
+        public Session onCreateSession(@NonNull SessionInfo sessionInfo) {
+            // Recreate a new CarContext, because the previous one would have been
+            // destroyed in an unbind-rebind scenario.
+            mCarContext = TestCarContext.createCarContext(mContext);
+            mSession = createTestSession();
+            mSessionController = new SessionController(mSession, mCarContext, new Intent());
+
+            mSessionInfo = sessionInfo;
+            return mSession;
+        }
+
+        @SuppressWarnings("deprecation")
+        @Override
+        @NonNull
+        public Session onCreateSession() {
+            throw new RuntimeException("This method should never be called");
+        }
+    }
 }
diff --git a/car/app/app/src/test/java/androidx/car/app/CarAppServiceTest.java b/car/app/app/src/test/java/androidx/car/app/CarAppServiceTest.java
index 9cc0d83..78ed56d 100644
--- a/car/app/app/src/test/java/androidx/car/app/CarAppServiceTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/CarAppServiceTest.java
@@ -20,7 +20,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.content.res.Configuration;
 
 import androidx.annotation.NonNull;
 import androidx.car.app.model.ItemList;
@@ -28,13 +27,18 @@
 import androidx.car.app.model.Template;
 import androidx.car.app.validation.HostValidator;
 import androidx.car.app.versioning.CarAppApiLevels;
+import androidx.test.core.app.ApplicationProvider;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ServiceController;
 import org.robolectric.annotation.internal.DoNotInstrument;
 
 
@@ -42,77 +46,118 @@
 @RunWith(RobolectricTestRunner.class)
 @DoNotInstrument
 public final class CarAppServiceTest {
-    @Mock
-    ICarHost mMockCarHost;
-    @Mock
-    IOnDoneCallback mMockOnDoneCallback;
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
 
-    private final Template mTemplate =
+    private static final HostInfo TEST_HOST_INFO = new HostInfo("foo", 1);
+    private static final Template TEST_RETURN_TEMPLATE =
             new PlaceListMapTemplate.Builder()
                     .setTitle("Title")
                     .setItemList(new ItemList.Builder().build())
                     .build();
+    private static final Session TEST_SESSION = new Session() {
+        @NonNull
+        @Override
+        public Screen onCreateScreen(@NonNull Intent intent) {
+            return new Screen(getCarContext()) {
+                @NonNull
+                @Override
+                public Template onGetTemplate() {
+                    return TEST_RETURN_TEMPLATE;
+                }
+            };
+        }
+    };
 
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+    @Mock
+    private ICarHost mMockCarHost;
+    @Mock
+    private IOnDoneCallback mMockOnDoneCallback;
     private CarAppService mCarAppService;
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mCarAppService =
-                new CarAppService() {
-                    @Override
-                    @NonNull
-                    public HostValidator createHostValidator() {
-                        return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR;
-                    }
-
-                    @Override
-                    @NonNull
-                    public Session onCreateSession() {
-                        // Recreate a new CarContext, because the previous one would have been
-                        // destroyed in an unbind-rebind scenario.
-                        return createTestSession();
-                    }
-                };
-        HostInfo hostInfo = new HostInfo("foo", 1);
-        mCarAppService.setHostInfo(hostInfo);
-        mCarAppService.onCreate();
-    }
-
-    private Session createTestSession() {
-        return new Session() {
-            @NonNull
-            @Override
-            public Screen onCreateScreen(@NonNull Intent intent) {
-                return new Screen(getCarContext()) {
-                    @Override
-                    @NonNull
-                    public Template onGetTemplate() {
-                        return mTemplate;
-                    }
-                };
-            }
-
-            @Override
-            void configure(@NonNull Context baseContext,
-                    @NonNull HandshakeInfo handshakeInfo,
-                    @NonNull HostInfo hostInfo,
-                    @NonNull ICarHost carHost,
-                    @NonNull Configuration configuration) {}
-        };
+        ServiceController<? extends CarAppService> serviceController =
+                Robolectric.buildService(TestCarAppService.class);
+        serviceController.get().setHostInfo(TEST_HOST_INFO);
+        mCarAppService = serviceController.create().get();
     }
 
     @Test
     public void onUnbind_destroysSession() {
-        CarAppBinder carApp = (CarAppBinder) mCarAppService.onBind(null);
+        CarAppBinder carApp = (CarAppBinder) mCarAppService.onBind(new Intent());
         carApp.setHandshakeInfo(new HandshakeInfo("foo",
                 CarAppApiLevels.getLatest()));
-        carApp.onAppCreate(mMockCarHost, null, new Configuration(), mMockOnDoneCallback);
+        carApp.onAppCreate(mMockCarHost, new Intent(), mContext.getResources().getConfiguration(),
+                mMockOnDoneCallback);
         carApp.onAppStart(mMockOnDoneCallback);
 
         assertThat(carApp.getCurrentSession()).isNotNull();
-        assertThat(mCarAppService.onUnbind(null)).isTrue();
+        assertThat(mCarAppService.onUnbind(new Intent())).isTrue();
 
         assertThat(carApp.getCurrentSession()).isNull();
     }
+
+    @Test
+    public void onBind() {
+        CarAppBinder result = (CarAppBinder) mCarAppService.onBind(new Intent());
+
+        assertThat(result.getCurrentSessionInfo()).isEqualTo(SessionInfo.DEFAULT_SESSION_INFO);
+    }
+
+    @Test
+    public void onCreateSession_withoutNewOnCreateSession_usesOldOnCreateSession() {
+        ServiceController<? extends CarAppService> serviceController =
+                Robolectric.buildService(TestCarAppServiceWithoutNewOnCreateSession.class);
+        serviceController.get().setHostInfo(TEST_HOST_INFO);
+        CarAppService oldSessionCarAppService = serviceController.create().get();
+
+        Session result = oldSessionCarAppService.onCreateSession(SessionInfo.DEFAULT_SESSION_INFO);
+
+        assertThat(result).isEqualTo(TEST_SESSION);
+    }
+
+    @Test
+    public void onCreateSession_doesNotCallOldMethod() {
+        Session result = mCarAppService.onCreateSession(SessionInfo.DEFAULT_SESSION_INFO);
+
+        assertThat(result).isEqualTo(TEST_SESSION);
+    }
+
+    private static class TestCarAppServiceWithoutNewOnCreateSession extends CarAppService {
+        @NonNull
+        @Override
+        public HostValidator createHostValidator() {
+            return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR;
+        }
+
+        @NonNull
+        @Override
+        @SuppressWarnings("deprecation")
+        public Session onCreateSession() {
+            return TEST_SESSION;
+        }
+    }
+
+    private static class TestCarAppService extends CarAppService {
+        @NonNull
+        @Override
+        public HostValidator createHostValidator() {
+            return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR;
+        }
+
+        @NonNull
+        @Override
+        @SuppressWarnings("deprecation")
+        public Session onCreateSession() {
+            throw new IllegalArgumentException("This should not be called");
+        }
+
+        @NonNull
+        @Override
+        public Session onCreateSession(@NonNull SessionInfo sessionInfo) {
+            return TEST_SESSION;
+        }
+    }
 }
diff --git a/car/app/app/src/test/java/androidx/car/app/SessionInfoTest.java b/car/app/app/src/test/java/androidx/car/app/SessionInfoTest.java
index 54d75f4..3712ac8 100644
--- a/car/app/app/src/test/java/androidx/car/app/SessionInfoTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/SessionInfoTest.java
@@ -16,6 +16,9 @@
 
 package androidx.car.app;
 
+import static androidx.car.app.SessionInfo.DISPLAY_TYPE_CLUSTER;
+import static androidx.car.app.SessionInfo.DISPLAY_TYPE_MAIN;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import androidx.car.app.model.Template;
@@ -35,15 +38,15 @@
 
     @Test
     public void dataClassTest() {
-        SessionInfo result = new SessionInfo(SessionInfo.DISPLAY_TYPE_MAIN, TEST_SESSION_ID);
+        SessionInfo result = new SessionInfo(DISPLAY_TYPE_MAIN, TEST_SESSION_ID);
 
         assertThat(result.getSessionId()).isEqualTo(TEST_SESSION_ID);
-        assertThat(result.getDisplayType()).isEqualTo(SessionInfo.DISPLAY_TYPE_MAIN);
+        assertThat(result.getDisplayType()).isEqualTo(DISPLAY_TYPE_MAIN);
     }
 
     @Test
     public void getSupportedTemplates_displayTypeMain() {
-        SessionInfo sessionInfo = new SessionInfo(SessionInfo.DISPLAY_TYPE_MAIN, TEST_SESSION_ID);
+        SessionInfo sessionInfo = new SessionInfo(DISPLAY_TYPE_MAIN, TEST_SESSION_ID);
 
         Set<Class<? extends Template>> result =
                 sessionInfo.getSupportedTemplates(CarAppApiLevels.LEVEL_5);
@@ -54,7 +57,7 @@
     @Test
     public void getSupportedTemplates_displayTypeCluster() {
         SessionInfo sessionInfo =
-                new SessionInfo(SessionInfo.DISPLAY_TYPE_CLUSTER, TEST_SESSION_ID);
+                new SessionInfo(DISPLAY_TYPE_CLUSTER, TEST_SESSION_ID);
 
         Set<Class<? extends Template>> result =
                 sessionInfo.getSupportedTemplates(CarAppApiLevels.LEVEL_5);
@@ -65,11 +68,58 @@
     @Test
     public void getSupportedTemplates_displayTypeCluster_apiLessThan5() {
         SessionInfo sessionInfo =
-                new SessionInfo(SessionInfo.DISPLAY_TYPE_CLUSTER, TEST_SESSION_ID);
+                new SessionInfo(DISPLAY_TYPE_CLUSTER, TEST_SESSION_ID);
 
         Set<Class<? extends Template>> result =
                 sessionInfo.getSupportedTemplates(CarAppApiLevels.LEVEL_4);
 
         assertThat(result).isEmpty();
     }
+
+    @Test
+    public void equals_comparedAgainstNull_isNotEqual() {
+        SessionInfo clusterSessionInfo = new SessionInfo(DISPLAY_TYPE_CLUSTER,
+                TEST_SESSION_ID);
+
+        assertThat(clusterSessionInfo).isNotEqualTo(null);
+    }
+
+    @Test
+    public void equals_sameIdDifferentDisplay_returnsFalse() {
+        SessionInfo clusterSessionInfo = new SessionInfo(DISPLAY_TYPE_CLUSTER,
+                TEST_SESSION_ID);
+        SessionInfo mainDisplaySessionInfo = new SessionInfo(DISPLAY_TYPE_MAIN,
+                TEST_SESSION_ID);
+        assertThat(clusterSessionInfo).isNotEqualTo(mainDisplaySessionInfo);
+    }
+
+    @Test
+    public void equals_sameDisplayDifferentId_returnsFalse() {
+        SessionInfo clusterSessionInfo = new SessionInfo(DISPLAY_TYPE_MAIN,
+                TEST_SESSION_ID);
+        SessionInfo mainDisplaySessionInfo = new SessionInfo(DISPLAY_TYPE_MAIN,
+                TEST_SESSION_ID + TEST_SESSION_ID);
+        assertThat(clusterSessionInfo).isNotEqualTo(mainDisplaySessionInfo);
+    }
+
+    @Test
+    public void toString_returnsCorrectFormat() {
+        SessionInfo displayTypeMainSessionId = new SessionInfo(DISPLAY_TYPE_MAIN, TEST_SESSION_ID);
+        SessionInfo anotherDiplayTypeMainSessionId = new SessionInfo(DISPLAY_TYPE_MAIN,
+                TEST_SESSION_ID);
+        String expected = DISPLAY_TYPE_MAIN + "/" + TEST_SESSION_ID;
+
+        assertThat(displayTypeMainSessionId.toString()).isEqualTo(expected);
+    }
+
+    @Test
+    public void toString_differentObjects_areEqual() {
+        SessionInfo displayTypeMainSessionId = new SessionInfo(DISPLAY_TYPE_MAIN, TEST_SESSION_ID);
+        SessionInfo anotherDisplayTypeMainSessionId = new SessionInfo(DISPLAY_TYPE_MAIN,
+                TEST_SESSION_ID);
+
+        assertThat(displayTypeMainSessionId.toString()).isEqualTo(
+                anotherDisplayTypeMainSessionId.toString());
+    }
+
 }
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/LongSparseArray.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/LongSparseArray.kt
new file mode 100644
index 0000000..e891076
--- /dev/null
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/LongSparseArray.kt
@@ -0,0 +1,605 @@
+/*
+ * Copyright 2018 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.collection
+
+import androidx.collection.internal.binarySearch
+import androidx.collection.internal.idealLongArraySize
+import kotlin.DeprecationLevel.HIDDEN
+import kotlin.jvm.JvmField
+import kotlin.jvm.JvmOverloads
+import kotlin.jvm.JvmSynthetic
+
+private val DELETED = Any()
+
+/**
+ * SparseArray mapping longs to Objects. Unlike a normal array of Objects, there can be gaps in the
+ * indices. It is intended to be more memory efficient than using a HashMap to map Longs to Objects,
+ * both because it avoids auto-boxing keys and its data structure doesn't rely on an extra entry
+ * object for each mapping.
+ *
+ * Note that this container keeps its mappings in an array data structure, using a binary search to
+ * find keys. The implementation is not intended to be appropriate for data structures that may
+ * contain large numbers of items. It is generally slower than a traditional HashMap, since lookups
+ * require a binary search and adds and removes require inserting and deleting entries in the array.
+ * For containers holding up to hundreds of items, the performance difference is not significant,
+ * less than 50%.
+ *
+ * To help with performance, the container includes an optimization when removing keys: instead of
+ * compacting its array immediately, it leaves the removed entry marked as deleted. The entry can
+ * then be re-used for the same key, or compacted later in a single garbage collection step of all
+ * removed entries. This garbage collection will need to be performed at any time the array needs to
+ * be grown or the map size or entry values are retrieved.
+ *
+ * It is possible to iterate over the items in this container using [keyAt] and [valueAt]. Iterating
+ * over the keys using [keyAt] with ascending values of the index will return the keys in ascending
+ * order, or the values corresponding to the keys in ascending order in the case of [valueAt].
+ *
+ * @constructor Creates a new [LongSparseArray] containing no mappings that will not require any
+ * additional memory allocation to store the specified number of mappings. If you supply an initial
+ * capacity of 0, the sparse array will be initialized with a light-weight representation not
+ * requiring any additional array allocations.
+ */
+public expect open class LongSparseArray<E>
+@JvmOverloads public constructor(initialCapacity: Int = 10) {
+    @JvmSynthetic // Hide from Java callers.
+    @JvmField
+    internal var garbage: Boolean
+
+    @JvmSynthetic // Hide from Java callers.
+    @JvmField
+    internal var keys: LongArray
+
+    @JvmSynthetic // Hide from Java callers.
+    @JvmField
+    internal var values: Array<Any?>
+
+    @JvmSynthetic // Hide from Java callers.
+    @JvmField
+    internal var size: Int
+
+    /**
+     * Gets the value mapped from the specified [key], or `null` if no such mapping has been made.
+     */
+    public open operator fun get(key: Long): E?
+
+    /**
+     * Gets the value mapped from the specified [key], or [defaultValue] if no such mapping has been
+     * made.
+     */
+    @Suppress("KotlinOperator") // Avoid confusion with matrix access syntax.
+    public open fun get(key: Long, defaultValue: E): E
+
+    /**
+     * Removes the mapping from the specified [key], if there was any.
+     */
+    @Deprecated("Alias for `remove(key)`.", ReplaceWith("remove(key)"))
+    public open fun delete(key: Long): Unit
+
+    /**
+     * Removes the mapping from the specified [key], if there was any.
+     */
+    public open fun remove(key: Long): Unit
+
+    /**
+     * Remove an existing key from the array map only if it is currently mapped to [value].
+     *
+     * @param key The key of the mapping to remove.
+     * @param value The value expected to be mapped to the key.
+     * @return Returns `true` if the mapping was removed.
+     */
+    public open fun remove(key: Long, value: E): Boolean
+
+    /**
+     * Removes the mapping at the specified [index].
+     */
+    public open fun removeAt(index: Int): Unit
+
+    /**
+     * Replace the mapping for [key] only if it is already mapped to a value.
+     *
+     * @param key The key of the mapping to replace.
+     * @param value The value to store for the given key.
+     * @return Returns the previous mapped value or `null`.
+     */
+    public open fun replace(key: Long, value: E): E?
+
+    /**
+     * Replace the mapping for [key] only if it is already mapped to a value.
+     *
+     * @param key The key of the mapping to replace.
+     * @param oldValue The value expected to be mapped to the key.
+     * @param newValue The value to store for the given key.
+     * @return Returns `true` if the value was replaced.
+     */
+    public open fun replace(key: Long, oldValue: E, newValue: E): Boolean
+
+    /**
+     * Adds a mapping from the specified key to the specified value, replacing the previous mapping
+     * from the specified key if there was one.
+     */
+    public open fun put(key: Long, value: E): Unit
+
+    /**
+     * Copies all of the mappings from [other] to this map. The effect of this call is equivalent to
+     * that of calling [put] on this map once for each mapping from key to value in [other].
+     */
+    public open fun putAll(other: LongSparseArray<out E>): Unit
+
+    /**
+     * Add a new value to the array map only if the key does not already have a value or it is
+     * mapped to `null`.
+     *
+     * @param key The key under which to store the value.
+     * @param value The value to store for the given key.
+     * @return Returns the value that was stored for the given key, or `null` if there was no such
+     * key.
+     */
+    public open fun putIfAbsent(key: Long, value: E): E?
+
+    /**
+     * Returns the number of key-value mappings that this [LongSparseArray] currently stores.
+     */
+    public open fun size(): Int
+
+    /**
+     * Return `true` if [size] is 0.
+     *
+     * @return `true` if [size] is 0.
+     */
+    public open fun isEmpty(): Boolean
+
+    /**
+     * Given an index in the range `0...size()-1`, returns the key from the `index`th key-value
+     * mapping that this [LongSparseArray] stores.
+     *
+     * The keys corresponding to indices in ascending order are guaranteed to be in ascending order,
+     * e.g., `keyAt(0)` will return the smallest key and `keyAt(size()-1)` will return the largest
+     * key.
+     *
+     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
+     */
+    public open fun keyAt(index: Int): Long
+
+    /**
+     * Given an index in the range `0...size()-1`, returns the value from the `index`th key-value
+     * mapping that this [LongSparseArray] stores.
+     *
+     * The values corresponding to indices in ascending order are guaranteed to be associated with
+     * keys in ascending order, e.g., `valueAt(0)` will return the value associated with the
+     * smallest key and `valueAt(size()-1)` will return the value associated with the largest key.
+     *
+     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
+     */
+    public open fun valueAt(index: Int): E
+
+    /**
+     * Given an index in the range `0...size()-1`, sets a new value for the `index`th key-value
+     * mapping that this [LongSparseArray] stores.
+     *
+     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
+     */
+    public open fun setValueAt(index: Int, value: E): Unit
+
+    /**
+     * Returns the index for which [keyAt] would return the
+     * specified key, or a negative number if the specified
+     * key is not mapped.
+     */
+    public open fun indexOfKey(key: Long): Int
+
+    /**
+     * Returns an index for which [valueAt] would return the specified key, or a negative number if
+     * no keys map to the specified [value].
+     *
+     * Beware that this is a linear search, unlike lookups by key, and that multiple keys can map to
+     * the same value and this will find only one of them.
+     */
+    public open fun indexOfValue(value: E): Int
+
+    /** Returns `true` if the specified [key] is mapped. */
+    public open fun containsKey(key: Long): Boolean
+
+    /** Returns `true` if the specified [value] is mapped from any key. */
+    public open fun containsValue(value: E): Boolean
+
+    /**
+     * Removes all key-value mappings from this [LongSparseArray].
+     */
+    public open fun clear(): Unit
+
+    /**
+     * Puts a key/value pair into the array, optimizing for the case where the key is greater than
+     * all existing keys in the array.
+     */
+    public open fun append(key: Long, value: E): Unit
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * This implementation composes a string by iterating over its mappings. If this map contains
+     * itself as a value, the string "(this Map)" will appear in its place.
+     */
+    override fun toString(): String
+}
+
+// TODO(KT-20427): Move these into the expect once support is added for default implementations.
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonGet(key: Long): E? {
+    return commonGetInternal(key, null)
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonGet(key: Long, defaultValue: E): E {
+    return commonGetInternal(key, defaultValue)
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <T : E?, E> LongSparseArray<E>.commonGetInternal(
+    key: Long,
+    defaultValue: T
+): T {
+    val i = binarySearch(keys, size, key)
+    return if (i < 0 || values[i] === DELETED) {
+        defaultValue
+    } else {
+        @Suppress("UNCHECKED_CAST")
+        values[i] as T
+    }
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonRemove(key: Long) {
+    val i = binarySearch(keys, size, key)
+    if (i >= 0) {
+        if (values[i] !== DELETED) {
+            values[i] = DELETED
+            garbage = true
+        }
+    }
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonRemove(key: Long, value: E): Boolean {
+    val index = indexOfKey(key)
+    if (index >= 0) {
+        val mapValue = valueAt(index)
+        if (value == mapValue) {
+            removeAt(index)
+            return true
+        }
+    }
+    return false
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonRemoveAt(index: Int) {
+    if (values[index] !== DELETED) {
+        values[index] = DELETED
+        garbage = true
+    }
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonReplace(key: Long, value: E): E? {
+    val index = indexOfKey(key)
+    if (index >= 0) {
+        @Suppress("UNCHECKED_CAST")
+        val oldValue = values[index] as E?
+        values[index] = value
+        return oldValue
+    }
+    return null
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonReplace(
+    key: Long,
+    oldValue: E,
+    newValue: E
+): Boolean {
+    val index = indexOfKey(key)
+    if (index >= 0) {
+        val mapValue = values[index]
+        if (mapValue == oldValue) {
+            values[index] = newValue
+            return true
+        }
+    }
+    return false
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonGc() {
+    val n = size
+    var newSize = 0
+    val keys = keys
+    val values = values
+    for (i in 0 until n) {
+        val value = values[i]
+        if (value !== DELETED) {
+            if (i != newSize) {
+                keys[newSize] = keys[i]
+                values[newSize] = value
+                values[i] = null
+            }
+            newSize++
+        }
+    }
+    garbage = false
+    size = newSize
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonPut(key: Long, value: E) {
+    var index = binarySearch(keys, size, key)
+    if (index >= 0) {
+        values[index] = value
+    } else {
+        index = index.inv()
+        if (index < size && values[index] === DELETED) {
+            keys[index] = key
+            values[index] = value
+            return
+        }
+        if (garbage && size >= keys.size) {
+            commonGc()
+
+            // Search again because indices may have changed.
+            index = binarySearch(keys, size, key).inv()
+        }
+        if (size >= keys.size) {
+            val newSize = idealLongArraySize(size + 1)
+            keys = keys.copyOf(newSize)
+            values = values.copyOf(newSize)
+        }
+        if (size - index != 0) {
+            keys.copyInto(
+                keys,
+                destinationOffset = index + 1,
+                startIndex = index,
+                endIndex = size
+            )
+            values.copyInto(
+                values,
+                destinationOffset = index + 1,
+                startIndex = index,
+                endIndex = size
+            )
+        }
+        keys[index] = key
+        values[index] = value
+        size++
+    }
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonPutAll(other: LongSparseArray<out E>) {
+    val size = other.size()
+    repeat(size) { i ->
+        put(other.keyAt(i), other.valueAt(i))
+    }
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonPutIfAbsent(key: Long, value: E): E? {
+    val mapValue = get(key)
+    if (mapValue == null) {
+        put(key, value)
+    }
+    return mapValue
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonSize(): Int {
+    if (garbage) {
+        commonGc()
+    }
+    return size
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonIsEmpty(): Boolean = size() == 0
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonKeyAt(index: Int): Long {
+    require(index in 0 until size) {
+        "Expected index to be within 0..size()-1, but was $index"
+    }
+
+    if (garbage) {
+        commonGc()
+    }
+    return keys[index]
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonValueAt(index: Int): E {
+    require(index in 0 until size) {
+        "Expected index to be within 0..size()-1, but was $index"
+    }
+
+    if (garbage) {
+        commonGc()
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    return values[index] as E
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonSetValueAt(index: Int, value: E) {
+    require(index in 0 until size) {
+        "Expected index to be within 0..size()-1, but was $index"
+    }
+
+    if (garbage) {
+        commonGc()
+    }
+    values[index] = value
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonIndexOfKey(key: Long): Int {
+    if (garbage) {
+        commonGc()
+    }
+    return binarySearch(keys, size, key)
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonIndexOfValue(value: E): Int {
+    if (garbage) {
+        commonGc()
+    }
+    repeat(size) { i ->
+        if (values[i] === value) {
+            return i
+        }
+    }
+    return -1
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonContainsKey(key: Long): Boolean {
+    return indexOfKey(key) >= 0
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonContainsValue(value: E): Boolean {
+    return indexOfValue(value) >= 0
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonClear() {
+    val n = size
+    val values = values
+    for (i in 0 until n) {
+        values[i] = null
+    }
+    size = 0
+    garbage = false
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonAppend(key: Long, value: E) {
+    if (size != 0 && key <= keys[size - 1]) {
+        put(key, value)
+        return
+    }
+    if (garbage && size >= keys.size) {
+        commonGc()
+    }
+    val pos = size
+    if (pos >= keys.size) {
+        val newSize = idealLongArraySize(pos + 1)
+        keys = keys.copyOf(newSize)
+        values = values.copyOf(newSize)
+    }
+    keys[pos] = key
+    values[pos] = value
+    size = pos + 1
+}
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun <E> LongSparseArray<E>.commonToString(): String {
+    if (size() <= 0) {
+        return "{}"
+    }
+    return buildString(size * 28) {
+        append('{')
+        for (i in 0 until size) {
+            if (i > 0) {
+                append(", ")
+            }
+            val key = keyAt(i)
+            append(key)
+            append('=')
+            val value: Any? = valueAt(i)
+            if (value !== this) {
+                append(value)
+            } else {
+                append("(this Map)")
+            }
+        }
+        append('}')
+    }
+}
+
+/** Returns the number of key/value pairs in the collection. */
+@Suppress("NOTHING_TO_INLINE")
+public inline val <T> LongSparseArray<T>.size: Int get() = size()
+
+/** Returns true if the collection contains [key]. */
+@Suppress("NOTHING_TO_INLINE")
+public inline operator fun <T> LongSparseArray<T>.contains(key: Long): Boolean = containsKey(key)
+
+/** Allows the use of the index operator for storing values in the collection. */
+@Suppress("NOTHING_TO_INLINE")
+public inline operator fun <T> LongSparseArray<T>.set(key: Long, value: T): Unit = put(key, value)
+
+/** Creates a new collection by adding or replacing entries from [other]. */
+public operator fun <T> LongSparseArray<T>.plus(other: LongSparseArray<T>): LongSparseArray<T> {
+    val new = LongSparseArray<T>(size() + other.size())
+    new.putAll(this)
+    new.putAll(other)
+    return new
+}
+
+/** Return the value corresponding to [key], or [defaultValue] when not present. */
+@Suppress("NOTHING_TO_INLINE")
+public inline fun <T> LongSparseArray<T>.getOrDefault(key: Long, defaultValue: T): T =
+    get(key, defaultValue)
+
+/** Return the value corresponding to [key], or from [defaultValue] when not present. */
+@Suppress("NOTHING_TO_INLINE")
+public inline fun <T> LongSparseArray<T>.getOrElse(key: Long, defaultValue: () -> T): T =
+    get(key) ?: defaultValue()
+
+/** Return true when the collection contains elements. */
+@Suppress("NOTHING_TO_INLINE")
+public inline fun <T> LongSparseArray<T>.isNotEmpty(): Boolean = !isEmpty()
+
+/** Removes the entry for [key] only if it is mapped to [value]. */
+@Suppress("EXTENSION_SHADOWED_BY_MEMBER") // Binary API compatibility.
+@Deprecated(
+    message = "Replaced with member function. Remove extension import!",
+    level = HIDDEN
+)
+public fun <T> LongSparseArray<T>.remove(key: Long, value: T): Boolean = remove(key, value)
+
+/** Performs the given [action] for each key/value entry. */
+@Suppress("NOTHING_TO_INLINE")
+public inline fun <T> LongSparseArray<T>.forEach(action: (key: Long, value: T) -> Unit) {
+    for (index in 0 until size()) {
+        action(keyAt(index), valueAt(index))
+    }
+}
+
+/** Return an iterator over the collection's keys. */
+public fun <T> LongSparseArray<T>.keyIterator(): LongIterator = object : LongIterator() {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun nextLong() = keyAt(index++)
+}
+
+/** Return an iterator over the collection's values. */
+public fun <T> LongSparseArray<T>.valueIterator(): Iterator<T> = object : Iterator<T> {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun next() = valueAt(index++)
+}
diff --git a/collection/collection/src/jvmTest/kotlin/androidx/collection/LongSparseArrayTest.kt b/collection/collection/src/commonTest/kotlin/androidx/collection/LongSparseArrayTest.kt
similarity index 91%
rename from collection/collection/src/jvmTest/kotlin/androidx/collection/LongSparseArrayTest.kt
rename to collection/collection/src/commonTest/kotlin/androidx/collection/LongSparseArrayTest.kt
index 8ee9605..f12e234 100644
--- a/collection/collection/src/jvmTest/kotlin/androidx/collection/LongSparseArrayTest.kt
+++ b/collection/collection/src/commonTest/kotlin/androidx/collection/LongSparseArrayTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * 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.
@@ -15,16 +15,12 @@
  */
 package androidx.collection
 
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertNotSame
-import org.junit.Assert.assertNull
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertNull
+import kotlin.test.assertTrue
 
-@RunWith(JUnit4::class)
 internal class LongSparseArrayTest {
     @Test
     fun getOrDefaultPrefersStoredValue() {
@@ -270,17 +266,4 @@
         assertEquals(1L, dest[1L])
         assertEquals("two", dest[2L])
     }
-
-    @Test
-    fun cloning() {
-        val source = LongSparseArray<String>()
-        source.put(10L, "hello")
-        source.put(20L, "world")
-        val dest = source.clone()
-        assertNotSame(source, dest)
-        repeat(source.size()) { i ->
-            assertEquals(source.keyAt(i), dest.keyAt(i))
-            assertEquals(source.valueAt(i), dest.valueAt(i))
-        }
-    }
 }
\ No newline at end of file
diff --git a/collection/collection/src/jvmMain/kotlin/androidx/collection/LongSparseArray.jvm.kt b/collection/collection/src/jvmMain/kotlin/androidx/collection/LongSparseArray.jvm.kt
new file mode 100644
index 0000000..a3c602f
--- /dev/null
+++ b/collection/collection/src/jvmMain/kotlin/androidx/collection/LongSparseArray.jvm.kt
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2018 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.collection
+
+import androidx.collection.internal.EMPTY_LONGS
+import androidx.collection.internal.EMPTY_OBJECTS
+import androidx.collection.internal.idealLongArraySize
+
+/**
+ * SparseArray mapping longs to Objects. Unlike a normal array of Objects, there can be gaps in the
+ * indices. It is intended to be more memory efficient than using a HashMap to map Longs to Objects,
+ * both because it avoids auto-boxing keys and its data structure doesn't rely on an extra entry
+ * object for each mapping.
+ *
+ * Note that this container keeps its mappings in an array data structure, using a binary search to
+ * find keys. The implementation is not intended to be appropriate for data structures that may
+ * contain large numbers of items. It is generally slower than a traditional HashMap, since lookups
+ * require a binary search and adds and removes require inserting and deleting entries in the array.
+ * For containers holding up to hundreds of items, the performance difference is not significant,
+ * less than 50%.
+ *
+ * To help with performance, the container includes an optimization when removing keys: instead of
+ * compacting its array immediately, it leaves the removed entry marked as deleted. The entry can
+ * then be re-used for the same key, or compacted later in a single garbage collection step of all
+ * removed entries. This garbage collection will need to be performed at any time the array needs to
+ * be grown or the map size or entry values are retrieved.
+ *
+ * It is possible to iterate over the items in this container using [keyAt] and [valueAt]. Iterating
+ * over the keys using [keyAt] with ascending values of the index will return the keys in ascending
+ * order, or the values corresponding to the keys in ascending order in the case of [valueAt].
+ *
+ * @constructor Creates a new [LongSparseArray] containing no mappings that will not require any
+ * additional memory allocation to store the specified number of mappings. If you supply an initial
+ * capacity of 0, the sparse array will be initialized with a light-weight representation not
+ * requiring any additional array allocations.
+ */
+public actual open class LongSparseArray<E>
+
+// TODO(b/237405792): Default value for optional argument is required here to workaround Metalava's
+//  lack of support for expect / actual.
+@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
+// TODO(b/237405286): @JvmOverloads is redundant in this actual, but is necessary here to workaround
+//  Metalava's lack of support for expect / actual.
+@JvmOverloads public actual constructor(initialCapacity: Int = 10) : Cloneable {
+    @JvmSynthetic // Hide from Java callers.
+    @JvmField
+    internal actual var garbage = false
+
+    @JvmSynthetic // Hide from Java callers.
+    @JvmField
+    internal actual var keys: LongArray
+
+    @JvmSynthetic // Hide from Java callers.
+    @JvmField
+    internal actual var values: Array<Any?>
+
+    @JvmSynthetic // Hide from Java callers.
+    @JvmField
+    internal actual var size = 0
+
+    init {
+        if (initialCapacity == 0) {
+            keys = EMPTY_LONGS
+            values = EMPTY_OBJECTS
+        } else {
+            val idealCapacity = idealLongArraySize(initialCapacity)
+            keys = LongArray(idealCapacity)
+            values = arrayOfNulls(idealCapacity)
+        }
+    }
+
+    public override fun clone(): LongSparseArray<E> {
+        @Suppress("UNCHECKED_CAST")
+        val clone: LongSparseArray<E> = super.clone() as LongSparseArray<E>
+        clone.keys = keys.clone()
+        clone.values = values.clone()
+        return clone
+    }
+
+    /**
+     * Gets the value mapped from the specified [key], or `null` if no such mapping has been made.
+     */
+    public actual open operator fun get(key: Long): E? = commonGet(key)
+
+    /**
+     * Gets the value mapped from the specified [key], or [defaultValue] if no such mapping has been
+     * made.
+     */
+    @Suppress("KotlinOperator") // Avoid confusion with matrix access syntax.
+    public actual open fun get(key: Long, defaultValue: E): E = commonGet(key, defaultValue)
+
+    /**
+     * Removes the mapping from the specified [key], if there was any.
+     */
+    @Deprecated("Alias for `remove(key)`.", ReplaceWith("remove(key)"))
+    public actual open fun delete(key: Long): Unit = commonRemove(key)
+
+    /**
+     * Removes the mapping from the specified [key], if there was any.
+     */
+    public actual open fun remove(key: Long): Unit = commonRemove(key)
+
+    /**
+     * Remove an existing key from the array map only if it is currently mapped to [value].
+     *
+     * @param key The key of the mapping to remove.
+     * @param value The value expected to be mapped to the key.
+     * @return Returns true if the mapping was removed.
+     */
+    public actual open fun remove(key: Long, value: E): Boolean = commonRemove(key, value)
+
+    /**
+     * Removes the mapping at the specified index.
+     */
+    public actual open fun removeAt(index: Int): Unit = commonRemoveAt(index)
+
+    /**
+     * Replace the mapping for [key] only if it is already mapped to a value.
+     *
+     * @param key The key of the mapping to replace.
+     * @param value The value to store for the given key.
+     * @return Returns the previous mapped value or `null`.
+     */
+    public actual open fun replace(key: Long, value: E): E? = commonReplace(key, value)
+
+    /**
+     * Replace the mapping for [key] only if it is already mapped to a value.
+     *
+     * @param key The key of the mapping to replace.
+     * @param oldValue The value expected to be mapped to the key.
+     * @param newValue The value to store for the given key.
+     * @return Returns `true` if the value was replaced.
+     */
+    public actual open fun replace(key: Long, oldValue: E, newValue: E): Boolean =
+        commonReplace(key, oldValue, newValue)
+
+    /**
+     * Adds a mapping from the specified key to the specified value, replacing the previous mapping
+     * from the specified key if there was one.
+     */
+    public actual open fun put(key: Long, value: E): Unit = commonPut(key, value)
+
+    /**
+     * Copies all of the mappings from [other] to this map. The effect of this call is equivalent to
+     * that of calling [put] on this map once for each mapping from key to value in [other].
+     */
+    public actual open fun putAll(other: LongSparseArray<out E>): Unit = commonPutAll(other)
+
+    /**
+     * Add a new value to the array map only if the key does not already have a value or it is
+     * mapped to `null`.
+     *
+     * @param key The key under which to store the value.
+     * @param value The value to store for the given key.
+     * @return Returns the value that was stored for the given key, or `null` if there was no such
+     * key.
+     */
+    public actual open fun putIfAbsent(key: Long, value: E): E? = commonPutIfAbsent(key, value)
+
+    /**
+     * Returns the number of key-value mappings that this [LongSparseArray] currently stores.
+     */
+    public actual open fun size(): Int = commonSize()
+
+    /**
+     * Return `true` if [size] is 0.
+     *
+     * @return `true` if [size] is 0.
+     */
+    public actual open fun isEmpty(): Boolean = commonIsEmpty()
+
+    /**
+     * Given an index in the range `0...size()-1`, returns the key from the `index`th key-value
+     * mapping that this [LongSparseArray] stores.
+     *
+     * The keys corresponding to indices in ascending order are guaranteed to be in ascending order,
+     * e.g., `keyAt(0)` will return the smallest key and `keyAt(size()-1)` will return the largest
+     * key.
+     *
+     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
+     */
+    public actual open fun keyAt(index: Int): Long = commonKeyAt(index)
+
+    /**
+     * Given an index in the range `0...size()-1`, returns the value from the `index`th key-value
+     * mapping that this [LongSparseArray] stores.
+     *
+     * The values corresponding to indices in ascending order are guaranteed to be associated with
+     * keys in ascending order, e.g., `valueAt(0)` will return the value associated with the
+     * smallest key and `valueAt(size()-1)` will return the value associated with the largest key.
+     *
+     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
+     */
+    public actual open fun valueAt(index: Int): E = commonValueAt(index)
+
+    /**
+     * Given an index in the range `0...size()-1`, sets a new value for the `index`th key-value
+     * mapping that this [LongSparseArray] stores.
+     *
+     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
+     */
+    public actual open fun setValueAt(index: Int, value: E): Unit = commonSetValueAt(index, value)
+
+    /**
+     * Returns the index for which [keyAt] would return the
+     * specified key, or a negative number if the specified
+     * key is not mapped.
+     */
+    public actual open fun indexOfKey(key: Long): Int = commonIndexOfKey(key)
+
+    /**
+     * Returns an index for which [valueAt] would return the specified key, or a negative number if
+     * no keys map to the specified [value].
+     *
+     * Beware that this is a linear search, unlike lookups by key, and that multiple keys can map to
+     * the same value and this will find only one of them.
+     */
+    public actual open fun indexOfValue(value: E): Int = commonIndexOfValue(value)
+
+    /** Returns `true` if the specified [key] is mapped. */
+    public actual open fun containsKey(key: Long): Boolean = commonContainsKey(key)
+
+    /** Returns `true` if the specified [value] is mapped from any key. */
+    public actual open fun containsValue(value: E): Boolean = commonContainsValue(value)
+
+    /**
+     * Removes all key-value mappings from this [LongSparseArray].
+     */
+    public actual open fun clear(): Unit = commonClear()
+
+    /**
+     * Puts a key/value pair into the array, optimizing for the case where the key is greater than
+     * all existing keys in the array.
+     */
+    public actual open fun append(key: Long, value: E): Unit = commonAppend(key, value)
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * This implementation composes a string by iterating over its mappings. If this map contains
+     * itself as a value, the string "(this Map)" will appear in its place.
+     */
+    actual override fun toString(): String = commonToString()
+}
\ No newline at end of file
diff --git a/collection/collection/src/jvmMain/kotlin/androidx/collection/LongSparseArray.kt b/collection/collection/src/jvmMain/kotlin/androidx/collection/LongSparseArray.kt
deleted file mode 100644
index c30e713..0000000
--- a/collection/collection/src/jvmMain/kotlin/androidx/collection/LongSparseArray.kt
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright 2018 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.collection
-
-import androidx.collection.internal.EMPTY_LONGS
-import androidx.collection.internal.EMPTY_OBJECTS
-import androidx.collection.internal.binarySearch
-import androidx.collection.internal.idealLongArraySize
-import kotlin.DeprecationLevel.HIDDEN
-
-private val DELETED = Any()
-
-/**
- * SparseArray mapping longs to Objects. Unlike a normal array of Objects, there can be gaps in the
- * indices. It is intended to be more memory efficient than using a HashMap to map Longs to Objects,
- * both because it avoids auto-boxing keys and its data structure doesn't rely on an extra entry
- * object for each mapping.
- *
- * Note that this container keeps its mappings in an array data structure, using a binary search to
- * find keys. The implementation is not intended to be appropriate for data structures that may
- * contain large numbers of items. It is generally slower than a traditional HashMap, since lookups
- * require a binary search and adds and removes require inserting and deleting entries in the array.
- * For containers holding up to hundreds of items, the performance difference is not significant,
- * less than 50%.
- *
- * To help with performance, the container includes an optimization when removing keys: instead of
- * compacting its array immediately, it leaves the removed entry marked as deleted. The entry can
- * then be re-used for the same key, or compacted later in a single garbage collection step of all
- * removed entries. This garbage collection will need to be performed at any time the array needs to
- * be grown or the map size or entry values are retrieved.
- *
- * It is possible to iterate over the items in this container using [keyAt] and [valueAt]. Iterating
- * over the keys using [keyAt] with ascending values of the index will return the keys in ascending
- * order, or the values corresponding to the keys in ascending order in the case of [valueAt].
- *
- * @constructor Creates a new [LongSparseArray] containing no mappings that will not require any
- * additional memory allocation to store the specified number of mappings. If you supply an initial
- * capacity of 0, the sparse array will be initialized with a light-weight representation not
- * requiring any additional array allocations.
- */
-public open class LongSparseArray<E>
-@JvmOverloads public constructor(initialCapacity: Int = 10) : Cloneable {
-    private var garbage = false
-    private var keys: LongArray
-    private var values: Array<Any?>
-    private var size = 0
-
-    init {
-        if (initialCapacity == 0) {
-            keys = EMPTY_LONGS
-            values = EMPTY_OBJECTS
-        } else {
-            val idealCapacity = idealLongArraySize(initialCapacity)
-            keys = LongArray(idealCapacity)
-            values = arrayOfNulls(idealCapacity)
-        }
-    }
-
-    public override fun clone(): LongSparseArray<E> {
-        @Suppress("UNCHECKED_CAST")
-        val clone: LongSparseArray<E> = super.clone() as LongSparseArray<E>
-        clone.keys = keys.clone()
-        clone.values = values.clone()
-        return clone
-    }
-
-    /**
-     * Gets the value mapped from the specified [key], or `null` if no such mapping has been made.
-     */
-    public open operator fun get(key: Long): E? {
-        return getInternal(key, null)
-    }
-
-    /**
-     * Gets the value mapped from the specified [key], or [defaultValue] if no such mapping has been
-     * made.
-     */
-    @Suppress("KotlinOperator") // Avoid confusion with matrix access syntax.
-    public open fun get(key: Long, defaultValue: E): E {
-        return getInternal(key, defaultValue)
-    }
-
-    @Suppress("NOTHING_TO_INLINE")
-    private inline fun <T : E?> getInternal(key: Long, defaultValue: T): T {
-        val i = binarySearch(keys, size, key)
-        return if (i < 0 || values[i] === DELETED) {
-            defaultValue
-        } else {
-            @Suppress("UNCHECKED_CAST")
-            values[i] as T
-        }
-    }
-
-    /**
-     * Removes the mapping from the specified [key], if there was any.
-     */
-    @Deprecated("Alias for `remove(key)`.", ReplaceWith("remove(key)"))
-    public open fun delete(key: Long) {
-        remove(key)
-    }
-
-    /**
-     * Removes the mapping from the specified [key], if there was any.
-     */
-    public open fun remove(key: Long) {
-        val i = binarySearch(keys, size, key)
-        if (i >= 0) {
-            if (values[i] !== DELETED) {
-                values[i] = DELETED
-                garbage = true
-            }
-        }
-    }
-
-    /**
-     * Remove an existing key from the array map only if it is currently mapped to [value].
-     *
-     * @param key The key of the mapping to remove.
-     * @param value The value expected to be mapped to the key.
-     * @return Returns true if the mapping was removed.
-     */
-    public open fun remove(key: Long, value: E): Boolean {
-        val index = indexOfKey(key)
-        if (index >= 0) {
-            val mapValue = valueAt(index)
-            if (value == mapValue) {
-                removeAt(index)
-                return true
-            }
-        }
-        return false
-    }
-
-    /**
-     * Removes the mapping at the specified index.
-     */
-    public open fun removeAt(index: Int) {
-        if (values[index] !== DELETED) {
-            values[index] = DELETED
-            garbage = true
-        }
-    }
-
-    /**
-     * Replace the mapping for [key] only if it is already mapped to a value.
-     *
-     * @param key The key of the mapping to replace.
-     * @param value The value to store for the given key.
-     * @return Returns the previous mapped value or `null`.
-     */
-    public open fun replace(key: Long, value: E): E? {
-        val index = indexOfKey(key)
-        if (index >= 0) {
-            @Suppress("UNCHECKED_CAST")
-            val oldValue = values[index] as E?
-            values[index] = value
-            return oldValue
-        }
-        return null
-    }
-
-    /**
-     * Replace the mapping for [key] only if it is already mapped to a value.
-     *
-     * @param key The key of the mapping to replace.
-     * @param oldValue The value expected to be mapped to the key.
-     * @param newValue The value to store for the given key.
-     * @return Returns `true` if the value was replaced.
-     */
-    public open fun replace(key: Long, oldValue: E, newValue: E): Boolean {
-        val index = indexOfKey(key)
-        if (index >= 0) {
-            val mapValue = values[index]
-            if (mapValue == oldValue) {
-                values[index] = newValue
-                return true
-            }
-        }
-        return false
-    }
-
-    private fun gc() {
-        // Log.e("SparseArray", "gc start with " + mSize);
-        val n = size
-        var newSize = 0
-        val keys = keys
-        val values = values
-        for (i in 0 until n) {
-            val value = values[i]
-            if (value !== DELETED) {
-                if (i != newSize) {
-                    keys[newSize] = keys[i]
-                    values[newSize] = value
-                    values[i] = null
-                }
-                newSize++
-            }
-        }
-        garbage = false
-        size = newSize
-
-        // Log.e("SparseArray", "gc end with " + mSize);
-    }
-
-    /**
-     * Adds a mapping from the specified key to the specified value, replacing the previous mapping
-     * from the specified key if there was one.
-     */
-    public open fun put(key: Long, value: E) {
-        var i = binarySearch(keys, size, key)
-        if (i >= 0) {
-            values[i] = value
-        } else {
-            i = i.inv()
-            if (i < size && values[i] === DELETED) {
-                keys[i] = key
-                values[i] = value
-                return
-            }
-            if (garbage && size >= keys.size) {
-                gc()
-
-                // Search again because indices may have changed.
-                i = binarySearch(keys, size, key).inv()
-            }
-            if (size >= keys.size) {
-                val n = idealLongArraySize(size + 1)
-                val nkeys = LongArray(n)
-                val nvalues = arrayOfNulls<Any>(n)
-
-                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-                System.arraycopy(keys, 0, nkeys, 0, keys.size)
-                System.arraycopy(values, 0, nvalues, 0, values.size)
-                keys = nkeys
-                values = nvalues
-            }
-            if (size - i != 0) {
-                // Log.e("SparseArray", "move " + (mSize - i));
-                System.arraycopy(keys, i, keys, i + 1, size - i)
-                System.arraycopy(values, i, values, i + 1, size - i)
-            }
-            keys[i] = key
-            values[i] = value
-            size++
-        }
-    }
-
-    /**
-     * Copies all of the mappings from [other] to this map. The effect of this call is equivalent to
-     * that of calling [put] on this map once for each mapping from key to value in [other].
-     */
-    public open fun putAll(other: LongSparseArray<out E>) {
-        val size = other.size()
-        repeat(size) { i ->
-            put(other.keyAt(i), other.valueAt(i))
-        }
-    }
-
-    /**
-     * Add a new value to the array map only if the key does not already have a value or it is
-     * mapped to `null`.
-     *
-     * @param key The key under which to store the value.
-     * @param value The value to store for the given key.
-     * @return Returns the value that was stored for the given key, or `null` if there was no such
-     * key.
-     */
-    public open fun putIfAbsent(key: Long, value: E): E? {
-        val mapValue = get(key)
-        if (mapValue == null) {
-            put(key, value)
-        }
-        return mapValue
-    }
-
-    /**
-     * Returns the number of key-value mappings that this [LongSparseArray] currently stores.
-     */
-    public open fun size(): Int {
-        if (garbage) {
-            gc()
-        }
-        return size
-    }
-
-    /**
-     * Return `true` if [size] is 0.
-     *
-     * @return `true` if [size] is 0.
-     */
-    public open fun isEmpty(): Boolean = size() == 0
-
-    /**
-     * Given an index in the range `0...size()-1`, returns the key from the `index`th key-value
-     * mapping that this [LongSparseArray] stores.
-     *
-     * The keys corresponding to indices in ascending order are guaranteed to be in ascending order,
-     * e.g., `keyAt(0)` will return the smallest key and `keyAt(size()-1)` will return the largest
-     * key.
-     *
-     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
-     */
-    public open fun keyAt(index: Int): Long {
-        require(index in 0 until size) {
-            "Expected index to be within 0..size()-1, but was $index"
-        }
-
-        if (garbage) {
-            gc()
-        }
-        return keys[index]
-    }
-
-    /**
-     * Given an index in the range `0...size()-1`, returns the value from the `index`th key-value
-     * mapping that this [LongSparseArray] stores.
-     *
-     * The values corresponding to indices in ascending order are guaranteed to be associated with
-     * keys in ascending order, e.g., `valueAt(0)` will return the value associated with the
-     * smallest key and `valueAt(size()-1)` will return the value associated with the largest key.
-     *
-     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
-     */
-    public open fun valueAt(index: Int): E {
-        require(index in 0 until size) {
-            "Expected index to be within 0..size()-1, but was $index"
-        }
-
-        if (garbage) {
-            gc()
-        }
-
-        @Suppress("UNCHECKED_CAST")
-        return values[index] as E
-    }
-
-    /**
-     * Given an index in the range `0...size()-1`, sets a new value for the `index`th key-value
-     * mapping that this [LongSparseArray] stores.
-     *
-     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
-     */
-    public open fun setValueAt(index: Int, value: E) {
-        require(index in 0 until size) {
-            "Expected index to be within 0..size()-1, but was $index"
-        }
-
-        if (garbage) {
-            gc()
-        }
-        values[index] = value
-    }
-
-    /**
-     * Returns the index for which [keyAt] would return the
-     * specified key, or a negative number if the specified
-     * key is not mapped.
-     */
-    public open fun indexOfKey(key: Long): Int {
-        if (garbage) {
-            gc()
-        }
-        return binarySearch(keys, size, key)
-    }
-
-    /**
-     * Returns an index for which [valueAt] would return the specified key, or a negative number if
-     * no keys map to the specified [value].
-     *
-     * Beware that this is a linear search, unlike lookups by key, and that multiple keys can map to
-     * the same value and this will find only one of them.
-     */
-    public open fun indexOfValue(value: E): Int {
-        if (garbage) {
-            gc()
-        }
-        repeat(size) { i ->
-            if (values[i] === value) {
-                return i
-            }
-        }
-        return -1
-    }
-
-    /** Returns `true` if the specified [key] is mapped. */
-    public open fun containsKey(key: Long): Boolean {
-        return indexOfKey(key) >= 0
-    }
-
-    /** Returns `true` if the specified [value] is mapped from any key. */
-    public open fun containsValue(value: E): Boolean {
-        return indexOfValue(value) >= 0
-    }
-
-    /**
-     * Removes all key-value mappings from this [LongSparseArray].
-     */
-    public open fun clear() {
-        val n = size
-        val values = values
-        for (i in 0 until n) {
-            values[i] = null
-        }
-        size = 0
-        garbage = false
-    }
-
-    /**
-     * Puts a key/value pair into the array, optimizing for the case where the key is greater than
-     * all existing keys in the array.
-     */
-    public open fun append(key: Long, value: E) {
-        if (size != 0 && key <= keys[size - 1]) {
-            put(key, value)
-            return
-        }
-        if (garbage && size >= keys.size) {
-            gc()
-        }
-        val pos = size
-        if (pos >= keys.size) {
-            val n = idealLongArraySize(pos + 1)
-            val nkeys = LongArray(n)
-            val nvalues = arrayOfNulls<Any>(n)
-
-            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-            System.arraycopy(keys, 0, nkeys, 0, keys.size)
-            System.arraycopy(values, 0, nvalues, 0, values.size)
-            keys = nkeys
-            values = nvalues
-        }
-        keys[pos] = key
-        values[pos] = value
-        size = pos + 1
-    }
-
-    /**
-     * Returns a string representation of the object.
-     *
-     * This implementation composes a string by iterating over its mappings. If this map contains
-     * itself as a value, the string "(this Map)" will appear in its place.
-     */
-    override fun toString(): String {
-        if (size() <= 0) {
-            return "{}"
-        }
-        return buildString(size * 28) {
-            append('{')
-            for (i in 0 until size) {
-                if (i > 0) {
-                    append(", ")
-                }
-                val key = keyAt(i)
-                append(key)
-                append('=')
-                val value: Any? = valueAt(i)
-                if (value !== this) {
-                    append(value)
-                } else {
-                    append("(this Map)")
-                }
-            }
-            append('}')
-        }
-    }
-}
-
-/** Returns the number of key/value pairs in the collection. */
-public inline val <T> LongSparseArray<T>.size: Int get() = size()
-
-/** Returns true if the collection contains [key]. */
-@Suppress("NOTHING_TO_INLINE")
-public inline operator fun <T> LongSparseArray<T>.contains(key: Long): Boolean = containsKey(key)
-
-/** Allows the use of the index operator for storing values in the collection. */
-@Suppress("NOTHING_TO_INLINE")
-public inline operator fun <T> LongSparseArray<T>.set(key: Long, value: T): Unit = put(key, value)
-
-/** Creates a new collection by adding or replacing entries from [other]. */
-public operator fun <T> LongSparseArray<T>.plus(other: LongSparseArray<T>): LongSparseArray<T> {
-    val new = LongSparseArray<T>(size() + other.size())
-    new.putAll(this)
-    new.putAll(other)
-    return new
-}
-
-/** Return the value corresponding to [key], or [defaultValue] when not present. */
-@Suppress("NOTHING_TO_INLINE")
-public inline fun <T> LongSparseArray<T>.getOrDefault(key: Long, defaultValue: T): T =
-    get(key, defaultValue)
-
-/** Return the value corresponding to [key], or from [defaultValue] when not present. */
-public inline fun <T> LongSparseArray<T>.getOrElse(key: Long, defaultValue: () -> T): T =
-    get(key) ?: defaultValue()
-
-/** Return true when the collection contains elements. */
-@Suppress("NOTHING_TO_INLINE")
-public inline fun <T> LongSparseArray<T>.isNotEmpty(): Boolean = !isEmpty()
-
-/** Removes the entry for [key] only if it is mapped to [value]. */
-@Suppress("EXTENSION_SHADOWED_BY_MEMBER") // Binary API compatibility.
-@Deprecated(
-    message = "Replaced with member function. Remove extension import!",
-    level = HIDDEN
-)
-public fun <T> LongSparseArray<T>.remove(key: Long, value: T): Boolean = remove(key, value)
-
-/** Performs the given [action] for each key/value entry. */
-public inline fun <T> LongSparseArray<T>.forEach(action: (key: Long, value: T) -> Unit) {
-    for (index in 0 until size()) {
-        action(keyAt(index), valueAt(index))
-    }
-}
-
-/** Return an iterator over the collection's keys. */
-public fun <T> LongSparseArray<T>.keyIterator(): LongIterator = object : LongIterator() {
-    var index = 0
-    override fun hasNext() = index < size()
-    override fun nextLong() = keyAt(index++)
-}
-
-/** Return an iterator over the collection's values. */
-public fun <T> LongSparseArray<T>.valueIterator(): Iterator<T> = object : Iterator<T> {
-    var index = 0
-    override fun hasNext() = index < size()
-    override fun next() = valueAt(index++)
-}
diff --git a/collection/collection/src/jvmTest/kotlin/androidx/collection/LongSparseArrayJvmTest.kt b/collection/collection/src/jvmTest/kotlin/androidx/collection/LongSparseArrayJvmTest.kt
new file mode 100644
index 0000000..df45728
--- /dev/null
+++ b/collection/collection/src/jvmTest/kotlin/androidx/collection/LongSparseArrayJvmTest.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.collection
+
+import kotlin.test.assertEquals
+import kotlin.test.assertNotSame
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+internal class LongSparseArrayJvmTest {
+    @Test
+    fun cloning() {
+        val source = LongSparseArray<String>()
+        source.put(10L, "hello")
+        source.put(20L, "world")
+        val dest = source.clone()
+        assertNotSame(source, dest)
+        repeat(source.size()) { i ->
+            assertEquals(source.keyAt(i), dest.keyAt(i))
+            assertEquals(source.valueAt(i), dest.valueAt(i))
+        }
+    }
+}
\ No newline at end of file
diff --git a/collection/collection/src/nativeMain/kotlin/androidx/collection/LongSparseArray.native.kt b/collection/collection/src/nativeMain/kotlin/androidx/collection/LongSparseArray.native.kt
new file mode 100644
index 0000000..1c6afd7
--- /dev/null
+++ b/collection/collection/src/nativeMain/kotlin/androidx/collection/LongSparseArray.native.kt
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2018 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.collection
+
+import androidx.collection.internal.EMPTY_LONGS
+import androidx.collection.internal.EMPTY_OBJECTS
+import androidx.collection.internal.idealLongArraySize
+
+/**
+ * SparseArray mapping longs to Objects. Unlike a normal array of Objects, there can be gaps in the
+ * indices. It is intended to be more memory efficient than using a HashMap to map Longs to Objects,
+ * both because it avoids auto-boxing keys and its data structure doesn't rely on an extra entry
+ * object for each mapping.
+ *
+ * Note that this container keeps its mappings in an array data structure, using a binary search to
+ * find keys. The implementation is not intended to be appropriate for data structures that may
+ * contain large numbers of items. It is generally slower than a traditional HashMap, since lookups
+ * require a binary search and adds and removes require inserting and deleting entries in the array.
+ * For containers holding up to hundreds of items, the performance difference is not significant,
+ * less than 50%.
+ *
+ * To help with performance, the container includes an optimization when removing keys: instead of
+ * compacting its array immediately, it leaves the removed entry marked as deleted. The entry can
+ * then be re-used for the same key, or compacted later in a single garbage collection step of all
+ * removed entries. This garbage collection will need to be performed at any time the array needs to
+ * be grown or the map size or entry values are retrieved.
+ *
+ * It is possible to iterate over the items in this container using [keyAt] and [valueAt]. Iterating
+ * over the keys using [keyAt] with ascending values of the index will return the keys in ascending
+ * order, or the values corresponding to the keys in ascending order in the case of [valueAt].
+ *
+ * @constructor Creates a new [LongSparseArray] containing no mappings that will not require any
+ * additional memory allocation to store the specified number of mappings. If you supply an initial
+ * capacity of 0, the sparse array will be initialized with a light-weight representation not
+ * requiring any additional array allocations.
+ */
+public actual open class LongSparseArray<E>
+public actual constructor(initialCapacity: Int) {
+    internal actual var garbage = false
+    internal actual var keys: LongArray
+    internal actual var values: Array<Any?>
+    internal actual var size = 0
+
+    init {
+        if (initialCapacity == 0) {
+            keys = EMPTY_LONGS
+            values = EMPTY_OBJECTS
+        } else {
+            val idealCapacity = idealLongArraySize(initialCapacity)
+            keys = LongArray(idealCapacity)
+            values = arrayOfNulls(idealCapacity)
+        }
+    }
+
+    /**
+     * Gets the value mapped from the specified [key], or `null` if no such mapping has been made.
+     */
+    public actual open operator fun get(key: Long): E? = commonGet(key)
+
+    /**
+     * Gets the value mapped from the specified [key], or [defaultValue] if no such mapping has been
+     * made.
+     */
+    @Suppress("KotlinOperator") // Avoid confusion with matrix access syntax.
+    public actual open fun get(key: Long, defaultValue: E): E = commonGet(key, defaultValue)
+
+    /**
+     * Removes the mapping from the specified [key], if there was any.
+     */
+    @Deprecated("Alias for `remove(key)`.", ReplaceWith("remove(key)"))
+    public actual open fun delete(key: Long): Unit = commonRemove(key)
+
+    /**
+     * Removes the mapping from the specified [key], if there was any.
+     */
+    public actual open fun remove(key: Long): Unit = commonRemove(key)
+
+    /**
+     * Remove an existing key from the array map only if it is currently mapped to [value].
+     *
+     * @param key The key of the mapping to remove.
+     * @param value The value expected to be mapped to the key.
+     * @return Returns true if the mapping was removed.
+     */
+    public actual open fun remove(key: Long, value: E): Boolean = commonRemove(key, value)
+
+    /**
+     * Removes the mapping at the specified index.
+     */
+    public actual open fun removeAt(index: Int): Unit = commonRemoveAt(index)
+
+    /**
+     * Replace the mapping for [key] only if it is already mapped to a value.
+     *
+     * @param key The key of the mapping to replace.
+     * @param value The value to store for the given key.
+     * @return Returns the previous mapped value or `null`.
+     */
+    public actual open fun replace(key: Long, value: E): E? = commonReplace(key, value)
+
+    /**
+     * Replace the mapping for [key] only if it is already mapped to a value.
+     *
+     * @param key The key of the mapping to replace.
+     * @param oldValue The value expected to be mapped to the key.
+     * @param newValue The value to store for the given key.
+     * @return Returns `true` if the value was replaced.
+     */
+    public actual open fun replace(key: Long, oldValue: E, newValue: E): Boolean =
+        commonReplace(key, oldValue, newValue)
+
+    /**
+     * Adds a mapping from the specified key to the specified value, replacing the previous mapping
+     * from the specified key if there was one.
+     */
+    public actual open fun put(key: Long, value: E): Unit = commonPut(key, value)
+
+    /**
+     * Copies all of the mappings from [other] to this map. The effect of this call is equivalent to
+     * that of calling [put] on this map once for each mapping from key to value in [other].
+     */
+    public actual open fun putAll(other: LongSparseArray<out E>): Unit = commonPutAll(other)
+
+    /**
+     * Add a new value to the array map only if the key does not already have a value or it is
+     * mapped to `null`.
+     *
+     * @param key The key under which to store the value.
+     * @param value The value to store for the given key.
+     * @return Returns the value that was stored for the given key, or `null` if there was no such
+     * key.
+     */
+    public actual open fun putIfAbsent(key: Long, value: E): E? = commonPutIfAbsent(key, value)
+
+    /**
+     * Returns the number of key-value mappings that this [LongSparseArray] currently stores.
+     */
+    public actual open fun size(): Int = commonSize()
+
+    /**
+     * Return `true` if [size] is 0.
+     *
+     * @return `true` if [size] is 0.
+     */
+    public actual open fun isEmpty(): Boolean = commonIsEmpty()
+
+    /**
+     * Given an index in the range `0...size()-1`, returns the key from the `index`th key-value
+     * mapping that this [LongSparseArray] stores.
+     *
+     * The keys corresponding to indices in ascending order are guaranteed to be in ascending order,
+     * e.g., `keyAt(0)` will return the smallest key and `keyAt(size()-1)` will return the largest
+     * key.
+     *
+     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
+     */
+    public actual open fun keyAt(index: Int): Long = commonKeyAt(index)
+
+    /**
+     * Given an index in the range `0...size()-1`, returns the value from the `index`th key-value
+     * mapping that this [LongSparseArray] stores.
+     *
+     * The values corresponding to indices in ascending order are guaranteed to be associated with
+     * keys in ascending order, e.g., `valueAt(0)` will return the value associated with the
+     * smallest key and `valueAt(size()-1)` will return the value associated with the largest key.
+     *
+     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
+     */
+    public actual open fun valueAt(index: Int): E = commonValueAt(index)
+
+    /**
+     * Given an index in the range `0...size()-1`, sets a new value for the `index`th key-value
+     * mapping that this [LongSparseArray] stores.
+     *
+     * @throws IllegalArgumentException if [index] is not in the range `0...size()-1`
+     */
+    public actual open fun setValueAt(index: Int, value: E): Unit = commonSetValueAt(index, value)
+
+    /**
+     * Returns the index for which [keyAt] would return the
+     * specified key, or a negative number if the specified
+     * key is not mapped.
+     */
+    public actual open fun indexOfKey(key: Long): Int = commonIndexOfKey(key)
+
+    /**
+     * Returns an index for which [valueAt] would return the specified key, or a negative number if
+     * no keys map to the specified [value].
+     *
+     * Beware that this is a linear search, unlike lookups by key, and that multiple keys can map to
+     * the same value and this will find only one of them.
+     */
+    public actual open fun indexOfValue(value: E): Int = commonIndexOfValue(value)
+
+    /** Returns `true` if the specified [key] is mapped. */
+    public actual open fun containsKey(key: Long): Boolean = commonContainsKey(key)
+
+    /** Returns `true` if the specified [value] is mapped from any key. */
+    public actual open fun containsValue(value: E): Boolean = commonContainsValue(value)
+
+    /**
+     * Removes all key-value mappings from this [LongSparseArray].
+     */
+    public actual open fun clear(): Unit = commonClear()
+
+    /**
+     * Puts a key/value pair into the array, optimizing for the case where the key is greater than
+     * all existing keys in the array.
+     */
+    public actual open fun append(key: Long, value: E): Unit = commonAppend(key, value)
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * This implementation composes a string by iterating over its mappings. If this map contains
+     * itself as a value, the string "(this Map)" will appear in its place.
+     */
+    actual override fun toString(): String = commonToString()
+}
\ No newline at end of file
diff --git a/compose/animation/animation-core/lint-baseline.xml b/compose/animation/animation-core/lint-baseline.xml
deleted file mode 100644
index 4352831..0000000
--- a/compose/animation/animation-core/lint-baseline.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 24 (current min is 21): `java.util.Collection#parallelStream`"
-        errorLine1="        testCases.parallelStream().forEach {"
-        errorLine2="                  ~~~~~~~~~~~~~~">
-        <location
-            file="src/test/java/androidx/compose/animation/core/SpringEstimationTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 24 (current min is 21): `java.util.stream.Stream#forEach`"
-        errorLine1="        testCases.parallelStream().forEach {"
-        errorLine2="                                   ~~~~~~~">
-        <location
-            file="src/test/java/androidx/compose/animation/core/SpringEstimationTest.kt"/>
-    </issue>
-
-</issues>
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Animation.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Animation.kt
index 6ca67a8..1c82541 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Animation.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Animation.kt
@@ -233,12 +233,19 @@
     override val isInfinite: Boolean get() = animationSpec.isInfinite
     override fun getValueFromNanos(playTimeNanos: Long): T {
         return if (!isFinishedFromNanos(playTimeNanos)) {
-            typeConverter.convertFromVector(
-                animationSpec.getValueFromNanos(
-                    playTimeNanos, initialValueVector,
-                    targetValueVector, initialVelocityVector
-                )
-            )
+            animationSpec.getValueFromNanos(
+                playTimeNanos, initialValueVector,
+                targetValueVector, initialVelocityVector
+            ).let {
+                // TODO: Remove after b/232030217
+                for (i in 0 until it.size) {
+                    check(!it.get(i).isNaN()) {
+                        "AnimationVector cannot contain a NaN. $it. Animation: $this," +
+                            " playTimeNanos: $playTimeNanos"
+                    }
+                }
+                typeConverter.convertFromVector(it)
+            }
         } else {
             targetValue
         }
@@ -272,7 +279,8 @@
 
     override fun toString(): String {
         return "TargetBasedAnimation: $initialValue -> $targetValue," +
-            "initial velocity: $initialVelocityVector, duration: $durationMillis ms"
+            "initial velocity: $initialVelocityVector, duration: $durationMillis ms," +
+            "animationSpec: $animationSpec"
     }
 }
 
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
index 6a00dfa..8276072 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
@@ -507,10 +507,15 @@
 
         internal fun onPlayTimeChanged(playTimeNanos: Long, durationScale: Float) {
             val playTime =
-                if (durationScale == 0f) {
-                    animation.durationNanos
+                if (durationScale > 0f) {
+                    val scaledTime = (playTimeNanos - offsetTimeNanos) / durationScale
+                    check(!scaledTime.isNaN()) {
+                        "Duration scale adjusted time is NaN. Duration scale: $durationScale," +
+                            "playTimeNanos: $playTimeNanos, offsetTimeNanos: $offsetTimeNanos"
+                    }
+                    scaledTime.toLong()
                 } else {
-                    ((playTimeNanos - offsetTimeNanos) / durationScale).toLong()
+                    animation.durationNanos
                 }
             value = animation.getValueFromNanos(playTime)
             velocityVector = animation.getVelocityVectorFromNanos(playTime)
diff --git a/compose/animation/animation/lint-baseline.xml b/compose/animation/animation/lint-baseline.xml
deleted file mode 100644
index a7f4be5..0000000
--- a/compose/animation/animation/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha01" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha01)" variant="all" version="7.4.0-alpha01">
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="private inline fun AnimatedEnterExitImpl("
-        errorLine2="                   ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt"/>
-    </issue>
-
-</issues>
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
index d44d4bb..ce4cfd3 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
@@ -43,6 +43,7 @@
 import java.net.URL
 import java.net.URLClassLoader
 import org.jetbrains.kotlin.cli.jvm.config.configureJdkClasspathRoots
+import org.jetbrains.kotlin.config.JVMConfigurationKeys
 
 private const val KOTLIN_RUNTIME_VERSION = "1.3.11"
 
@@ -292,6 +293,8 @@
         TEST_MODULE_NAME
     )
 
+    configuration.put(JVMConfigurationKeys.VALIDATE_IR, true)
+
     configuration.put(
         CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY,
         object : MessageCollector {
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt
index a63c76e..5bd414a 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt
@@ -77,25 +77,31 @@
     open val decoysEnabled get() = false
     open val metricsDestination: String? get() = null
 
-    protected val extension = ComposeIrGenerationExtension(
-        liveLiteralsEnabled,
-        liveLiteralsV2Enabled,
-        generateFunctionKeyMetaClasses,
-        sourceInformationEnabled,
-        intrinsicRememberEnabled,
-        decoysEnabled,
-        metricsDestination
-    )
+    protected var extension: ComposeIrGenerationExtension? = null
     // Some tests require the plugin context in order to perform assertions, for example, a
     // context is required to determine the stability of a type using the StabilityInferencer.
     var pluginContext: IrPluginContext? = null
 
+    override fun setUp() {
+        super.setUp()
+        extension = ComposeIrGenerationExtension(
+            myEnvironment!!.configuration,
+            liveLiteralsEnabled,
+            liveLiteralsV2Enabled,
+            generateFunctionKeyMetaClasses,
+            sourceInformationEnabled,
+            intrinsicRememberEnabled,
+            decoysEnabled,
+            metricsDestination
+        )
+    }
+
     override fun postProcessingStep(
         module: IrModuleFragment,
         context: IrPluginContext
     ) {
         pluginContext = context
-        extension.generate(
+        extension!!.generate(
             module,
             context
         )
@@ -103,6 +109,7 @@
 
     override fun tearDown() {
         pluginContext = null
+        extension = null
         super.tearDown()
     }
 }
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMetricsTransformTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMetricsTransformTest.kt
index 8e04c2e..415f0a1 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMetricsTransformTest.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMetricsTransformTest.kt
@@ -27,7 +27,7 @@
         module: IrModuleFragment,
         context: IrPluginContext
     ) {
-        extension.metrics = ModuleMetricsImpl(module.name.asString(), context)
+        extension!!.metrics = ModuleMetricsImpl(module.name.asString(), context)
         super.postProcessingStep(module, context)
     }
 
@@ -40,7 +40,7 @@
             sourceFile("Test.kt", source.replace('%', '$')),
         )
         compilation.compile(files)
-        extension.metrics.verify()
+        extension!!.metrics.verify()
     }
 
     fun assertClasses(
@@ -104,7 +104,7 @@
     }
 
     override fun tearDown() {
+        extension!!.metrics = EmptyModuleMetrics
         super.tearDown()
-        extension.metrics = EmptyModuleMetrics
     }
 }
\ No newline at end of file
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
index aceb657..bf549ed 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
@@ -562,7 +562,6 @@
         module: IrModuleFragment,
         context: IrPluginContext
     ) {
-        @Suppress("DEPRECATION")
         val symbolRemapper = DeepCopySymbolRemapper()
         val keyVisitor = DurableKeyVisitor(builtKeys)
         val transformer = object : LiveLiteralTransformer(
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralV2TransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralV2TransformTests.kt
index 9a46677..e8b2913 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralV2TransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralV2TransformTests.kt
@@ -564,7 +564,6 @@
         module: IrModuleFragment,
         context: IrPluginContext
     ) {
-        @Suppress("DEPRECATION")
         val symbolRemapper = DeepCopySymbolRemapper()
         val keyVisitor = DurableKeyVisitor(builtKeys)
         val transformer = object : LiveLiteralTransformer(
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TargetAnnotationsTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TargetAnnotationsTransformTests.kt
index 0f25426..05baa8c 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TargetAnnotationsTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TargetAnnotationsTransformTests.kt
@@ -1323,6 +1323,67 @@
         """
     )
 
+    @Test
+    fun testInferringTargetFromAncestorMethod() = verifyComposeIrTransform(
+        source = """
+            import androidx.compose.runtime.Composable
+            import androidx.compose.runtime.ComposableTarget
+            import androidx.compose.runtime.ComposableOpenTarget
+
+            @Composable @ComposableOpenTarget(0) fun OpenTarget() { }
+
+            abstract class Base {
+              @Composable @ComposableTarget("N") abstract fun Compose()
+            }
+
+            class Valid : Base () {
+              @Composable override fun Compose() {
+                OpenTarget()
+              }
+            }
+        """,
+        expectedTransformed = """
+            @Composable
+            @ComposableOpenTarget(index = 0)
+            fun OpenTarget(%composer: Composer?, %changed: Int) {
+              %composer = %composer.startRestartGroup(<>)
+              sourceInformation(%composer, "C(OpenTarget):Test.kt")
+              if (%changed !== 0 || !%composer.skipping) {
+              } else {
+                %composer.skipToGroupEnd()
+              }
+              %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                OpenTarget(%composer, %changed or 0b0001)
+              }
+            }
+            @StabilityInferred(parameters = 0)
+            abstract class Base {
+              @Composable
+              @ComposableTarget(applier = "N")
+              abstract fun Compose(%composer: Composer?, %changed: Int)
+              static val %stable: Int = 0
+            }
+            @StabilityInferred(parameters = 0)
+            class Valid : Base {
+              @Composable
+              override fun Compose(%composer: Composer?, %changed: Int) {
+                %composer = %composer.startRestartGroup(<>)
+                sourceInformation(%composer, "C(Compose)<OpenTa...>:Test.kt")
+                if (%changed and 0b0001 !== 0 || !%composer.skipping) {
+                  OpenTarget(%composer, 0)
+                } else {
+                  %composer.skipToGroupEnd()
+                }
+                val tmp0_rcvr = <this>
+                %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                  tmp0_rcvr.Compose(%composer, %changed or 0b0001)
+                }
+              }
+              static val %stable: Int = 0
+            }
+        """
+        )
+
     private fun verify(source: String, expected: String) =
         verifyComposeIrTransform(source, expected, baseDefinition)
 
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableTargetCheckerTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableTargetCheckerTests.kt
index 7063bcbc..d9f2f9e 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableTargetCheckerTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableTargetCheckerTests.kt
@@ -417,4 +417,73 @@
         }
         """
     )
+
+    fun testOpenOverrideAttributesInheritTarget() = check(
+        """
+        import androidx.compose.runtime.Composable
+        import androidx.compose.runtime.ComposableTarget
+
+        @Composable @ComposableTarget("N") fun N() { }
+        @Composable @ComposableTarget("M") fun M() { }
+
+        abstract class Base {
+          @Composable @ComposableTarget("N") abstract fun Compose()
+        }
+
+        class Invalid : Base() {
+          @Composable override fun Compose() {
+            <!COMPOSE_APPLIER_CALL_MISMATCH!>M<!>()
+          }
+        }
+
+        class Valid : Base () {
+          @Composable override fun Compose() {
+            N()
+          }
+        }
+        """
+    )
+
+    fun testOpenOverrideTargetsMustAgree() = check(
+        """
+        import androidx.compose.runtime.Composable
+        import androidx.compose.runtime.ComposableTarget
+
+        @Composable @ComposableTarget("N") fun N() { }
+        @Composable @ComposableTarget("M") fun M() { }
+
+        abstract class Base {
+          @Composable @ComposableTarget("N") abstract fun Compose()
+        }
+
+        class Invalid : Base() {
+          <!COMPOSE_APPLIER_DECLARATION_MISMATCH!>@Composable @ComposableTarget("M") override fun Compose() { }<!>
+        }
+
+        class Valid : Base () {
+          @Composable override fun Compose() {
+            N()
+          }
+        }
+        """
+    )
+
+    fun testOpenOverrideInferredToAgree() = check(
+        """
+        import androidx.compose.runtime.Composable
+        import androidx.compose.runtime.ComposableTarget
+
+        @Composable @ComposableTarget("N") fun N() { }
+        @Composable @ComposableTarget("M") fun M() { }
+
+        abstract class Base {
+          @Composable @ComposableTarget("N") abstract fun Compose()
+        }
+
+        class Invalid : Base() {
+          @Composable override fun Compose() {
+            N()
+          }
+        }
+        """)
 }
\ No newline at end of file
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
index 30952f6..6f2e72c 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
@@ -85,6 +85,10 @@
                         listOf(descriptor, override)
                     )
                 )
+            } else if (!descriptor.toScheme(null).canOverride(override.toScheme(null))) {
+                context.trace.report(
+                    ComposeErrors.COMPOSE_APPLIER_DECLARATION_MISMATCH.on(declaration)
+                )
             }
 
             descriptor.valueParameters.forEach { valueParameter ->
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 9dcd05c..bd9e032 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
@@ -428,13 +428,13 @@
 
 private fun Annotated.scheme(): Scheme? = compositionScheme()?.let { deserializeScheme(it) }
 
-private fun CallableDescriptor.toScheme(callContext: CallCheckerContext): Scheme =
+internal fun CallableDescriptor.toScheme(callContext: CallCheckerContext?): Scheme =
     scheme()
         ?: Scheme(
             target = schemeItem().let {
                 // The item is unspecified see if the containing has an annotation we can use
                 if (it.isUnspecified) {
-                    val target = fileScopeTarget(callContext)
+                    val target = callContext?.let { context -> fileScopeTarget(context) }
                     if (target != null) return@let target
                 }
                 it
@@ -444,15 +444,15 @@
             }.map {
                 it.samComposableOrNull()?.toScheme(callContext) ?: it.type.toScheme()
             }
-        )
+        ).mergeWith(overriddenDescriptors.map { it.toScheme(null) })
 
 private fun CallableDescriptor.fileScopeTarget(callContext: CallCheckerContext): Item? =
     (psiElement?.containingFile as? KtFile)?.let {
         for (entry in it.annotationEntries) {
             val annotationDescriptor =
                 callContext.trace.bindingContext[BindingContext.ANNOTATION, entry]
-            annotationDescriptor?.compositionTarget()?.let {
-                return Token(it)
+            annotationDescriptor?.compositionTarget()?.let { token ->
+                return Token(token)
             }
         }
         null
@@ -470,3 +470,24 @@
 
 private fun ValueParameterDescriptor.isSamComposable() =
     samComposableOrNull()?.hasComposableAnnotation() == true
+
+internal fun Scheme.mergeWith(schemes: List<Scheme>): Scheme {
+    if (schemes.isEmpty()) return this
+
+    val lazyScheme = LazyScheme(this)
+    val bindings = lazyScheme.bindings
+
+    fun unifySchemes(a: LazyScheme, b: LazyScheme) {
+        bindings.unify(a.target, b.target)
+        for ((ap, bp) in a.parameters.zip(b.parameters)) {
+            unifySchemes(ap, bp)
+        }
+    }
+
+    schemes.forEach {
+        val overrideScheme = LazyScheme(it, bindings = lazyScheme.bindings)
+        unifySchemes(lazyScheme, overrideScheme)
+    }
+
+    return lazyScheme.toScheme()
+}
\ No newline at end of file
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt
index 726ae5b..0398542 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt
@@ -120,5 +120,9 @@
             Renderers.TO_STRING,
             Renderers.TO_STRING
         )
+        MAP.put(
+            ComposeErrors.COMPOSE_APPLIER_DECLARATION_MISMATCH,
+            "The composition target of an override must match the ancestor target"
+        )
     }
 }
\ No newline at end of file
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt
index 3bfd5b6..3b3f96dd 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt
@@ -148,6 +148,12 @@
             Severity.WARNING
         )
 
+    @JvmField
+    val COMPOSE_APPLIER_DECLARATION_MISMATCH =
+        DiagnosticFactory0.create<PsiElement>(
+            Severity.WARNING
+        )
+
     init {
         Errors.Initializer.initializeFactoryNamesAndDefaultErrorMessages(
             ComposeErrors::class.java,
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
index d4561d2d..5e9e19a 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
@@ -37,6 +37,8 @@
 import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
 import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer
 import org.jetbrains.kotlin.backend.common.serialization.signature.PublicIdSignatureComputer
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.config.JVMConfigurationKeys
 import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsGlobalDeclarationTable
 import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
 import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
@@ -44,6 +46,7 @@
 import org.jetbrains.kotlin.platform.jvm.isJvm
 
 class ComposeIrGenerationExtension(
+    private val configuration: CompilerConfiguration,
     @Suppress("unused") private val liveLiteralsEnabled: Boolean = false,
     @Suppress("unused") private val liveLiteralsV2Enabled: Boolean = false,
     private val generateFunctionKeyMetaClasses: Boolean = false,
@@ -62,6 +65,11 @@
         val isKlibTarget = !pluginContext.platform.isJvm()
         VersionChecker(pluginContext).check()
 
+        // Input check.  This should always pass, else something is horribly wrong upstream.
+        // Necessary because oftentimes the issue is upstream (compiler bug, prior plugin, etc)
+        if (configuration.getBoolean(JVMConfigurationKeys.VALIDATE_IR))
+            validateIr(moduleFragment, pluginContext.irBuiltIns)
+
         // create a symbol remapper to be used across all transforms
         val symbolRemapper = ComposableSymbolRemapper()
 
@@ -200,5 +208,9 @@
         if (reportsDestination != null) {
             metrics.saveReportsTo(reportsDestination)
         }
+
+        // Verify that our transformations didn't break something
+        if (configuration.getBoolean(JVMConfigurationKeys.VALIDATE_IR))
+            validateIr(moduleFragment, pluginContext.irBuiltIns)
     }
 }
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
index 5a64b1c..44c0a94 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
@@ -291,6 +291,7 @@
             IrGenerationExtension.registerExtension(
                 project,
                 ComposeIrGenerationExtension(
+                    configuration = configuration,
                     liveLiteralsEnabled = liveLiteralsEnabled,
                     liveLiteralsV2Enabled = liveLiteralsV2Enabled,
                     generateFunctionKeyMetaClasses = generateFunctionKeyMetaClasses,
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/IrValidator.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/IrValidator.kt
new file mode 100644
index 0000000..797c82d
--- /dev/null
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/IrValidator.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.compiler.plugins.kotlin
+
+import androidx.compose.compiler.plugins.kotlin.lower.dumpSrc
+import org.jetbrains.kotlin.backend.common.CheckIrElementVisitor
+import org.jetbrains.kotlin.backend.common.IrValidatorConfig
+import org.jetbrains.kotlin.backend.common.ScopeValidator
+import org.jetbrains.kotlin.backend.common.checkDeclarationParents
+import org.jetbrains.kotlin.ir.IrBuiltIns
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.declarations.IrFile
+import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
+import org.jetbrains.kotlin.ir.declarations.name
+import org.jetbrains.kotlin.ir.util.render
+import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
+import org.jetbrains.kotlin.ir.visitors.acceptVoid
+
+fun validateIr(fragment: IrModuleFragment, irBuiltIns: IrBuiltIns) {
+    val validatorConfig = IrValidatorConfig(
+        abortOnError = true,
+        ensureAllNodesAreDifferent = true,
+        checkTypes = false, // This should be enabled, the fact this doesn't work is a Compose bug.
+        checkDescriptors = false,
+        checkProperties = true,
+        checkScopes = false
+    )
+    fragment.accept(IrValidator(irBuiltIns, validatorConfig), null)
+    fragment.checkDeclarationParents()
+}
+
+// TODO: Replace with IrValidator validator when upstream is compatible with PluginContext
+class IrValidator(val irBuiltIns: IrBuiltIns, val config: IrValidatorConfig) :
+    IrElementVisitorVoid {
+
+    var currentFile: IrFile? = null
+
+    override fun visitFile(declaration: IrFile) {
+        currentFile = declaration
+        super.visitFile(declaration)
+        if (config.checkScopes) {
+            ScopeValidator(this::error).check(declaration)
+        }
+    }
+
+    private fun error(element: IrElement, message: String) {
+        throw Error(
+            "Validation error ($message) for ${element.dumpSrc()}...  ${element.render()} in" +
+                " ${currentFile?.name ?: "???"}"
+        )
+    }
+
+    private val elementChecker = CheckIrElementVisitor(irBuiltIns, this::error, config)
+
+    override fun visitElement(element: IrElement) {
+        element.acceptVoid(elementChecker)
+        element.acceptChildrenVoid(this)
+    }
+}
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 68effb1..a3f863c 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
@@ -26,8 +26,8 @@
 
     companion object {
         /**
-         * A table of version ints to version strings. This should be updated every time
-         * ComposeVersion.kt is updated.
+         * A table of runtime version ints to version strings. This should be
+         * updated every time ComposeVersion.kt is updated.
          */
         private val versionTable = mapOf(
             1600 to "0.1.0-dev16",
@@ -80,6 +80,8 @@
             6900 to "1.2.0-beta02",
             7000 to "1.2.0-beta03",
             7100 to "1.2.0-rc01",
+            7101 to "1.2.0-rc02",
+            7102 to "1.2.0-rc03",
             8000 to "1.3.0-alpha01",
         )
 
@@ -93,7 +95,7 @@
          * The maven version string of this compiler. This string should be updated before/after every
          * release.
          */
-        const val compilerVersion: String = "1.2.0"
+        const val compilerVersion: String = "1.3.0-beta01"
         private val minimumRuntimeVersion: String
             get() = versionTable[minimumRuntimeVersionInt] ?: "unknown"
     }
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/inference/Scheme.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/inference/Scheme.kt
index 67e3a5e..b1a6a30 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/inference/Scheme.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/inference/Scheme.kt
@@ -112,8 +112,22 @@
         return this.alphaRename().simpleEquals(o.alphaRename())
     }
 
+    fun canOverride(other: Scheme): Boolean = alphaRename().simpleCanOverride(other.alphaRename())
+
     override fun hashCode(): Int = alphaRename().simpleHashCode()
 
+    private fun simpleCanOverride(other: Scheme): Boolean {
+        return if (other.target is Open) {
+            target is Open && other.target.index == target.index
+        } else {
+            target.isUnspecified || target == other.target
+        } && parameters.zip(other.parameters).all { (a, b) -> a.simpleCanOverride(b) } &&
+            (
+                result == other.result ||
+                    (other.result != null && result != null && result.canOverride((other.result)))
+            )
+    }
+
     private fun simpleEquals(other: Scheme) =
         target == other.target && parameters.zip(other.parameters).all { (a, b) -> a == b } &&
             result == result
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
index 4d40f46..16ef215 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
@@ -124,6 +124,7 @@
 import org.jetbrains.kotlin.ir.types.defaultType
 import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
 import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
+import org.jetbrains.kotlin.ir.types.isMarkedNullable
 import org.jetbrains.kotlin.ir.types.isNullable
 import org.jetbrains.kotlin.ir.types.isPrimitiveType
 import org.jetbrains.kotlin.ir.types.makeNullable
@@ -156,7 +157,6 @@
 import org.jetbrains.kotlin.util.OperatorNameConventions
 import org.jetbrains.kotlin.utils.DFS
 
-@Suppress("DEPRECATION")
 abstract class AbstractComposeLowering(
     val context: IrPluginContext,
     val symbolRemapper: DeepCopySymbolRemapper,
@@ -271,7 +271,7 @@
         when (this) {
             is IrSimpleType -> IrSimpleTypeImpl(
                 classifier,
-                hasQuestionMark,
+                isMarkedNullable(),
                 List(arguments.size) { IrStarProjectionImpl },
                 annotations,
                 abbreviation
@@ -451,7 +451,6 @@
         body: IrBlockBodyBuilder.(IrFunction) -> Unit
     ) = irLambdaExpression(this.startOffset, this.endOffset, descriptor, type, body)
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     protected fun IrBuilderWithScope.irLambdaExpression(
         startOffset: Int,
         endOffset: Int,
@@ -599,7 +598,6 @@
         )
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     protected fun irCall(
         symbol: IrFunctionSymbol,
         origin: IrStatementOrigin? = null,
@@ -624,11 +622,9 @@
         }
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     protected fun IrType.binaryOperator(name: Name, paramType: IrType): IrFunctionSymbol =
         context.symbols.getBinaryOperator(name, this, paramType)
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     protected fun IrType.unaryOperator(name: Name): IrFunctionSymbol =
         context.symbols.getUnaryOperator(name, this)
 
@@ -1033,7 +1029,6 @@
         )
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     protected fun irLambda(function: IrFunction, type: IrType): IrExpression {
         return irBlock(
             type,
@@ -1306,7 +1301,6 @@
 
 @OptIn(ObsoleteDescriptorBasedAPI::class)
 fun IrValueParameter.isComposerParam(): Boolean =
-    @Suppress("DEPRECATION")
     (descriptor as? ValueParameterDescriptor)?.isComposerParam() ?: false
 
 fun ValueParameterDescriptor.isComposerParam(): Boolean =
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
index 5438837..14cb8e5 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
@@ -46,6 +46,7 @@
 import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
 import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
 import org.jetbrains.kotlin.descriptors.Modality
+import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
 import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
 import org.jetbrains.kotlin.descriptors.SourceElement
 import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -470,7 +471,6 @@
  * of every function is also marked to correspond to indicate that the group corresponds to a call
  * and the source location of the caller can be determined from the containing group.
  */
-@Suppress("DEPRECATION")
 class ComposableFunctionBodyTransformer(
     context: IrPluginContext,
     symbolRemapper: DeepCopySymbolRemapper,
@@ -671,7 +671,7 @@
     private fun printScopeStack(): String {
         return buildString {
             currentScope.forEach {
-                appendln(it.name)
+                appendLine(it.name)
             }
         }
     }
@@ -1597,11 +1597,13 @@
             initialize(
                 null,
                 null,
+                emptyList<ReceiverParameterDescriptor>(),
                 emptyList(),
                 listOf(passedInComposerParameter, ignoredChangedParameter),
                 updateScopeBlockType.toKotlinType(),
                 Modality.FINAL,
-                DescriptorVisibilities.LOCAL
+                DescriptorVisibilities.LOCAL,
+                null
             )
         }
 
@@ -1855,7 +1857,6 @@
         return hash
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun functionSourceKey(): Int {
         val fn = currentFunctionScope.function
         if (fn is IrSimpleFunction) {
@@ -1986,7 +1987,6 @@
         return irMethodCall(irCurrentComposer(), endRestartGroupFunction)
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun irCache(
         startOffset: Int,
         endOffset: Int,
@@ -2115,7 +2115,6 @@
         )
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun irCall(
         function: IrFunction,
         startOffset: Int = UNDEFINED_OFFSET,
@@ -3723,7 +3722,7 @@
 
             private fun packageHash(): Int =
                 packageName()?.fold(0) { hash, current ->
-                    hash * 31 + current.toInt()
+                    hash * 31 + current.code
                 }?.absoluteValue ?: 0
 
             internal fun sourceFileInformation(): String {
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTargetAnnotationsTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTargetAnnotationsTransformer.kt
index ae67ced..24e0a00 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTargetAnnotationsTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTargetAnnotationsTransformer.kt
@@ -33,6 +33,7 @@
 import androidx.compose.compiler.plugins.kotlin.inference.Token
 import androidx.compose.compiler.plugins.kotlin.inference.deserializeScheme
 import androidx.compose.compiler.plugins.kotlin.irTrace
+import androidx.compose.compiler.plugins.kotlin.mergeWith
 import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
 import org.jetbrains.kotlin.descriptors.ClassKind
 import org.jetbrains.kotlin.descriptors.Modality
@@ -43,6 +44,7 @@
 import org.jetbrains.kotlin.ir.declarations.IrFunction
 import org.jetbrains.kotlin.ir.declarations.IrLocalDelegatedProperty
 import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
+import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
 import org.jetbrains.kotlin.ir.declarations.IrValueParameter
 import org.jetbrains.kotlin.ir.declarations.IrVariable
 import org.jetbrains.kotlin.ir.declarations.name
@@ -60,6 +62,7 @@
 import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
 import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
 import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
+import org.jetbrains.kotlin.ir.interpreter.getLastOverridden
 import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
 import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
 import org.jetbrains.kotlin.ir.symbols.IrSymbol
@@ -660,33 +663,41 @@
     }
 
     override fun toDeclaredScheme(defaultTarget: Item): Scheme = with(transformer) {
-        function.scheme
-            ?: run {
-                val target = function.annotations.target.let { target ->
-                    if (target.isUnspecified && function.body == null) {
-                        defaultTarget
-                    } else if (target.isUnspecified) {
-                        // Default to the target specified at the file scope, if one.
-                        function.file.annotations.target
-                    } else target
-                }
-                val effectiveDefault =
-                    if (function.body == null) defaultTarget
-                    else Open(-1, isUnspecified = true)
-                val result = function.returnType.let { resultType ->
-                    if (resultType.isOrHasComposableLambda)
-                        resultType.toScheme(effectiveDefault)
-                    else null
-                }
-
-                Scheme(
-                    target,
-                    parameters().map { it.toDeclaredScheme(effectiveDefault) },
-                    result
-                )
-            }
+        function.scheme ?: function.toScheme(defaultTarget)
     }
 
+    private fun IrFunction.toScheme(defaultTarget: Item): Scheme = with(transformer) {
+        val target = function.annotations.target.let { target ->
+            if (target.isUnspecified && function.body == null) {
+                defaultTarget
+            } else if (target.isUnspecified) {
+                // Default to the target specified at the file scope, if one.
+                function.file.annotations.target
+            } else target
+        }
+        val effectiveDefault =
+            if (function.body == null) defaultTarget
+            else Open(-1, isUnspecified = true)
+        val result = function.returnType.let { resultType ->
+            if (resultType.isOrHasComposableLambda)
+                resultType.toScheme(effectiveDefault)
+            else null
+        }
+
+        Scheme(
+            target,
+            parameters().map { it.toDeclaredScheme(effectiveDefault) },
+            result
+        ).let { scheme ->
+            ancestorScheme(defaultTarget)?.let { scheme.mergeWith(listOf(it)) } ?: scheme
+        }
+    }
+
+    private fun IrFunction.ancestorScheme(defaultTarget: Item): Scheme? =
+        if (this is IrSimpleFunction && this.overriddenSymbols.isNotEmpty()) {
+            getLastOverridden().toScheme(defaultTarget)
+        } else null
+
     override fun hashCode(): Int = function.hashCode() * 31
     override fun equals(other: Any?) =
         other is InferenceFunctionDeclaration && other.function == function
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
index 89384c6..cb0bb80 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
@@ -180,7 +180,6 @@
     @OptIn(ObsoleteDescriptorBasedAPI::class)
     override fun visitCall(expression: IrCall): IrCall {
         val ownerFn = expression.symbol.owner as? IrSimpleFunction
-        @Suppress("DEPRECATION")
         val containingClass = expression.symbol.descriptor.containingDeclaration as? ClassDescriptor
 
         // Any virtual calls on composable functions we want to make sure we update the call to
@@ -353,7 +352,6 @@
     private fun KotlinType.toIrType(): IrType = typeTranslator.translateType(this)
 }
 
-@Suppress("DEPRECATION")
 class ComposerTypeRemapper(
     private val context: IrPluginContext,
     private val symbolRemapper: SymbolRemapper,
@@ -377,7 +375,6 @@
         return annotations.hasAnnotation(ComposeFqNames.Composable)
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private val IrConstructorCall.annotationClass
         get() = this.symbol.owner.returnType.classifierOrNull
 
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
index 04818ff..16bb2f3 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
@@ -59,7 +59,6 @@
 
     @OptIn(ObsoleteDescriptorBasedAPI::class)
     override fun visitCall(expression: IrCall): IrExpression {
-        @Suppress("DEPRECATION")
         val calleeFqName = expression.symbol.descriptor.fqNameSafe
         if (calleeFqName == currentComposerIntrinsic) {
             // since this call was transformed by the ComposerParamTransformer, the first argument
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
index d3215535..0d6e9d2 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
@@ -390,7 +390,6 @@
         return result
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun irCurrentComposer(): IrExpression {
         val currentComposerSymbol = getTopLevelPropertyGetter(
             ComposeFqNames.fqNameFor("currentComposer")
@@ -814,7 +813,6 @@
         }
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun rememberExpression(
         functionContext: FunctionContext,
         expression: IrExpression,
@@ -1020,7 +1018,6 @@
         return this
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun IrExpression?.isNullOrStable() = this == null || stabilityOf(this).knownStable()
 }
 
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
index a834316..e3a5ab0 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
@@ -93,7 +93,6 @@
 import org.jetbrains.kotlin.resolve.multiplatform.findCompatibleExpectsForActual
 import org.jetbrains.kotlin.util.OperatorNameConventions
 
-@Suppress("DEPRECATION")
 class ComposerParamTransformer(
     context: IrPluginContext,
     symbolRemapper: DeepCopySymbolRemapper,
@@ -278,7 +277,7 @@
         endOffset: Int = UNDEFINED_OFFSET
     ): IrExpression {
         val classSymbol = classOrNull
-        if (this !is IrSimpleType || hasQuestionMark || !isInlineClassType()) {
+        if (this !is IrSimpleType || isMarkedNullable() || !isInlineClassType()) {
             return if (isMarkedNullable()) {
                 IrConstImpl.constNull(startOffset, endOffset, context.irBuiltIns.nothingNType)
             } else {
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
index 5acafa0..b535bdc 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
@@ -112,6 +112,7 @@
 import org.jetbrains.kotlin.utils.Printer
 import java.util.Locale
 import kotlin.math.abs
+import org.jetbrains.kotlin.ir.types.isMarkedNullable
 
 fun IrElement.dumpSrc(): String {
     val sb = StringBuilder()
@@ -131,7 +132,6 @@
         .replace(Regex("}\\n(\\s)*,", RegexOption.MULTILINE), "},")
 }
 
-@Suppress("DEPRECATION")
 class IrSourcePrinterVisitor(
     out: Appendable,
     indentUnit: String = "  ",
@@ -206,11 +206,11 @@
                 declaration.visibility != DescriptorVisibilities.PUBLIC &&
                 declaration.visibility != DescriptorVisibilities.LOCAL
             ) {
-                print(declaration.visibility.toString().toLowerCase(Locale.ROOT))
+                print(declaration.visibility.toString().lowercase(Locale.ROOT))
                 print(" ")
             }
             if (declaration.modality != Modality.FINAL) {
-                print(declaration.modality.toString().toLowerCase(Locale.ROOT))
+                print(declaration.modality.toString().lowercase(Locale.ROOT))
                 print(" ")
             }
         }
@@ -266,7 +266,6 @@
 
     private var isInNotCall = false
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     override fun visitCall(expression: IrCall) {
         val function = expression.symbol.owner
         val name = function.name.asString()
@@ -772,7 +771,6 @@
         println("}")
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     override fun visitReturn(expression: IrReturn) {
         val value = expression.value
         // only print the return statement directly if it is not a lambda
@@ -879,7 +877,7 @@
             declaration.visibility != DescriptorVisibilities.PUBLIC &&
             declaration.visibility != DescriptorVisibilities.LOCAL
         ) {
-            print(declaration.visibility.toString().toLowerCase(Locale.ROOT))
+            print(declaration.visibility.toString().lowercase(Locale.ROOT))
             print(" ")
         }
         if (declaration.isStatic) {
@@ -1055,7 +1053,7 @@
             declaration.visibility != DescriptorVisibilities.PUBLIC &&
             declaration.visibility != DescriptorVisibilities.LOCAL
         ) {
-            print(declaration.visibility.toString().toLowerCase(Locale.ROOT))
+            print(declaration.visibility.toString().lowercase(Locale.ROOT))
             print(" ")
         }
         if (declaration.isInner) {
@@ -1070,7 +1068,7 @@
             print("object ")
         } else {
             if (declaration.modality != Modality.FINAL) {
-                print(declaration.modality.toString().toLowerCase(Locale.ROOT))
+                print(declaration.modality.toString().lowercase(Locale.ROOT))
                 print(" ")
             }
             if (declaration.isAnnotationClass) {
@@ -1321,7 +1319,7 @@
                         }
                     )
                 }
-                if (hasQuestionMark) {
+                if (isMarkedNullable()) {
                     append('?')
                 }
                 abbreviation?.let {
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
index 60220e4..f540715 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
@@ -240,7 +240,6 @@
         putValueArgument(0, irConst(file))
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun irLiveLiteralGetter(
         key: String,
         literalValue: IrExpression,
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
index 620fcd5..3644fe5 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
@@ -165,7 +165,6 @@
         }
     }
 
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
     private fun IrFunction.decoyImplementationName(): Name {
         return dexSafeName(
             Name.identifier(name.asString() + IMPLEMENTATION_FUNCTION_SUFFIX)
diff --git a/compose/foundation/foundation-layout/lint-baseline.xml b/compose/foundation/foundation-layout/lint-baseline.xml
deleted file mode 100644
index 4073808..0000000
--- a/compose/foundation/foundation-layout/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 26 (current min is 21): `waitAndScreenShot`"
-        errorLine1="        val bitmap = activityTestRule.waitAndScreenShot()"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/BoxWithConstraintsTest.kt"/>
-    </issue>
-
-</issues>
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/DrawTextDemo.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/DrawTextDemo.kt
new file mode 100644
index 0000000..aaae8f1
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/DrawTextDemo.kt
@@ -0,0 +1,323 @@
+/*
+ * 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.
+ */
+@file:OptIn(ExperimentalTextApi::class)
+
+package androidx.compose.foundation.demos.text
+
+import androidx.compose.animation.animateColor
+import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.material.Checkbox
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshotFlow
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawscope.translate
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.drawText
+import androidx.compose.ui.text.rememberTextMeasurer
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
+import kotlin.math.roundToLong
+import kotlin.system.measureNanoTime
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.withIndex
+
+@Preview
+@Composable
+fun DrawTextDemo() {
+    LazyColumn {
+        item {
+            TagLine(tag = "Draw text string")
+            DrawTextString()
+        }
+        item {
+            TagLine(tag = "Draw text long string")
+            DrawTextLongString()
+        }
+        item {
+            TagLine(tag = "Draw text AnnotatedString")
+            DrawTextAnnotatedString()
+        }
+        item {
+            TagLine(tag = "DrawText measure")
+            DrawTextMeasure()
+        }
+
+        item {
+            TagLine(tag = "DrawText and animate color")
+            DrawTextAndAnimateColor()
+        }
+        item {
+            TagLine(tag = "DrawText measure and animate color")
+            DrawTextMeasureAndAnimateColor()
+        }
+    }
+}
+
+@Composable
+fun DrawTextString() {
+    val textMeasurer = rememberTextMeasurer()
+    Canvas(
+        Modifier
+            .fillMaxWidth()
+            .height(100.dp)
+    ) {
+        drawRect(brush = Brush.linearGradient(RainbowColors))
+        val padding = 16.dp.toPx()
+
+        drawText(
+            textMeasurer,
+            text = "Hello, World!",
+            topLeft = Offset(padding, padding),
+            style = TextStyle(fontSize = fontSize8)
+        )
+    }
+}
+
+@Composable
+fun DrawTextLongString() {
+    val textMeasurer = rememberTextMeasurer()
+    Canvas(
+        Modifier
+            .fillMaxWidth()
+            .height(100.dp)
+    ) {
+        drawRect(color = Color.Gray)
+        val padding = 16.dp.toPx()
+
+        drawText(
+            textMeasurer,
+            text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin fringilla " +
+                "laoreet aliquam. Aliquam ut nisl aliquet, laoreet tellus quis, sagittis enim. " +
+                "Sed sem dolor, tempus blandit purus suscipit, convallis tincidunt purus. Donec " +
+                "mattis placerat arcu sed consectetur. Pellentesque eu turpis lacus.",
+            topLeft = Offset(padding, padding),
+            style = TextStyle(fontSize = fontSize6),
+            overflow = TextOverflow.Visible,
+            size = IntSize((size.width - 2 * padding).toInt(), (size.height - 2 * padding).toInt())
+        )
+    }
+}
+
+@Composable
+fun DrawTextAnnotatedString() {
+    val textMeasurer = rememberTextMeasurer()
+    val text = remember {
+        buildAnnotatedString {
+            append("Hello World\n")
+            withStyle(
+                SpanStyle(brush = Brush.linearGradient(colors = RainbowColors))
+            ) {
+                append("Hello World")
+            }
+            append("\nHello World")
+        }
+    }
+    Canvas(
+        Modifier
+            .fillMaxWidth()
+            .height(100.dp)
+    ) {
+        drawRect(brush = Brush.linearGradient(RainbowColors))
+        val padding = 16.dp.toPx()
+
+        translate(padding, padding) {
+            drawText(textMeasurer, text, style = TextStyle(fontSize = fontSize6))
+        }
+    }
+}
+
+@Composable
+fun DrawTextMeasure() {
+    val textMeasurer = rememberTextMeasurer()
+    var textLayoutResult by remember { mutableStateOf<TextLayoutResult?>(null) }
+
+    Canvas(
+        Modifier
+            .fillMaxWidth()
+            .height(100.dp)
+            .layout { measurable, constraints ->
+                val placeable = measurable.measure(constraints)
+                textLayoutResult = textMeasurer.measure(
+                    AnnotatedString("Hello, World!"),
+                    style = TextStyle(fontSize = fontSize8)
+                )
+                layout(placeable.width, placeable.height) {
+                    placeable.placeRelative(0, 0)
+                }
+            }) {
+        drawRect(brush = Brush.linearGradient(RainbowColors))
+        val padding = 16.dp.toPx()
+
+        textLayoutResult?.let { drawText(it, topLeft = Offset(padding, padding)) }
+    }
+}
+
+@Composable
+fun DrawTextAndAnimateColor() {
+    val infiniteTransition = rememberInfiniteTransition()
+    val color by infiniteTransition.animateColor(
+        initialValue = Color.Red,
+        targetValue = Color.Blue,
+        animationSpec = infiniteRepeatable(tween(3000), RepeatMode.Reverse)
+    )
+
+    var skipCache by remember { mutableStateOf(false) }
+    val textMeasurer = rememberTextMeasurer(cacheSize = if (skipCache) 0 else 16)
+
+    val totalMeasurer = remember(skipCache) { AverageDurationMeasurer() }
+    val averageTotalDuration by totalMeasurer.averageDurationFlow.collectAsState(0L)
+
+    Column {
+        Text("Average total duration: $averageTotalDuration ns")
+        Row(verticalAlignment = Alignment.CenterVertically) {
+            Checkbox(checked = skipCache, onCheckedChange = { skipCache = it })
+            Text(text = "Skip Cache")
+        }
+        Canvas(
+            Modifier
+                .fillMaxWidth()
+                .height(100.dp)) {
+            drawRect(brush = Brush.linearGradient(RainbowColors))
+            val padding = 16.dp.toPx()
+
+            val duration = measureNanoTime {
+                drawText(
+                    textMeasurer,
+                    text = AnnotatedString("Hello, World!"),
+                    style = TextStyle(color = color, fontSize = fontSize8),
+                    topLeft = Offset(padding, padding)
+                )
+            }
+            totalMeasurer.addMeasure(duration)
+        }
+    }
+}
+
+@Composable
+fun DrawTextMeasureAndAnimateColor() {
+    val textMeasurer = rememberTextMeasurer()
+    var textLayoutResult by remember { mutableStateOf<TextLayoutResult?>(null) }
+    val infiniteTransition = rememberInfiniteTransition()
+    val color by infiniteTransition.animateColor(
+        initialValue = Color.Red,
+        targetValue = Color.Blue,
+        animationSpec = infiniteRepeatable(tween(3000), RepeatMode.Reverse)
+    )
+
+    var skipCache by remember { mutableStateOf(false) }
+    val layoutMeasurer = remember(skipCache) { AverageDurationMeasurer() }
+    val drawMeasurer = remember(skipCache) { AverageDurationMeasurer() }
+
+    val averageLayoutDuration by layoutMeasurer.averageDurationFlow.collectAsState(0L)
+    val averageDrawDuration by drawMeasurer.averageDurationFlow.collectAsState(0L)
+
+    Column {
+        Text("Average layout duration: $averageLayoutDuration ns")
+        Text("Average draw duration: $averageDrawDuration ns")
+        Text("Average total duration: ${averageLayoutDuration + averageDrawDuration} ns")
+        Row(verticalAlignment = Alignment.CenterVertically) {
+            Checkbox(checked = skipCache, onCheckedChange = { skipCache = it })
+            Text(text = "Skip Cache")
+        }
+        Canvas(
+            Modifier
+                .fillMaxWidth()
+                .height(100.dp)
+                .layout { measurable, constraints ->
+                    val placeable = measurable.measure(constraints)
+                    val duration = measureNanoTime {
+                        textLayoutResult = textMeasurer.measure(
+                            AnnotatedString("Hello, World!"),
+                            style = TextStyle(fontSize = fontSize8),
+                            skipCache = skipCache
+                        )
+                    }
+                    layoutMeasurer.addMeasure(duration)
+                    layout(placeable.width, placeable.height) {
+                        placeable.placeRelative(0, 0)
+                    }
+                }) {
+            drawRect(brush = Brush.linearGradient(RainbowColors))
+            val padding = 16.dp.toPx()
+
+            textLayoutResult?.let {
+                val duration = measureNanoTime {
+                    drawText(it, topLeft = Offset(padding, padding), color = color)
+                }
+                drawMeasurer.addMeasure(duration)
+            }
+        }
+    }
+}
+
+class AverageDurationMeasurer(private val capacity: Int = 600 /*60 fps * 10 seconds*/) {
+    private val values = mutableStateListOf<Long>()
+
+    fun addMeasure(duration: Long) {
+        values.add(duration)
+        while (values.size > capacity) {
+            values.removeFirst()
+        }
+    }
+
+    val current = derivedStateOf {
+        if (values.isEmpty()) 0L else values.average().roundToLong()
+    }
+
+    val averageDurationFlow = snapshotFlow { current.value }.withIndex().map { (index, value) ->
+        if (index % 60 == 0) value else null
+    }.filterNotNull()
+}
+
+private val RainbowColors = listOf(
+    Color(0xff9c4f96),
+    Color(0xffff6355),
+    Color(0xfffba949),
+    Color(0xfffae442),
+    Color(0xff8bd448),
+    Color(0xff2aa8f2)
+)
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
index 898b9cd..d510c3b 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
@@ -23,6 +23,7 @@
     "Text",
     listOf(
         ComposableDemo("Static text") { TextDemo() },
+        ComposableDemo("Canvas") { DrawTextDemo() },
         ComposableDemo("Brush") { TextBrushDemo() },
         ComposableDemo("Ellipsize") { EllipsizeDemo() },
         ComposableDemo("Typeface") { TypefaceDemo() },
@@ -62,4 +63,4 @@
         ),
         ComposableDemo("Text Accessibility") { TextAccessibilityDemo() }
     )
-)
\ No newline at end of file
+)
diff --git a/compose/foundation/foundation/lint-baseline.xml b/compose/foundation/foundation/lint-baseline.xml
deleted file mode 100644
index cf66848..0000000
--- a/compose/foundation/foundation/lint-baseline.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha01" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha01)" variant="all" version="7.4.0-alpha01">
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T> List&lt;T>.fastFilter(predicate: (T) -> Boolean): List&lt;T> {"
-        errorLine2="                                ~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/foundation/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, R> List&lt;T>.fastFold(initial: R, operation: (acc: R, T) -> R): R {"
-        errorLine2="                                   ~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/foundation/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, R> List&lt;T>.fastMapIndexedNotNull("
-        errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/foundation/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, R : Comparable&lt;R>> List&lt;T>.fastMaxOfOrNull(selector: (T) -> R): R? {"
-        errorLine2="                                                   ~~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/foundation/TempListUtils.kt"/>
-    </issue>
-
-</issues>
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
index 046d991..1c96893 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/OverscrollTest.kt
@@ -33,7 +33,9 @@
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.ImageBitmap
 import androidx.compose.ui.graphics.toPixelMap
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import androidx.compose.ui.input.nestedscroll.nestedScroll
 import androidx.compose.ui.platform.LocalView
 import androidx.compose.ui.platform.LocalViewConfiguration
 import androidx.compose.ui.platform.ViewConfiguration
@@ -448,6 +450,144 @@
         }
     }
 
+    @Test
+    fun horizontalOverscrollEnabled_verifyOverscrollReceivedSingleAxisValues() {
+        val controller = TestOverscrollEffect()
+        val scrollableState = ScrollableState { 0f }
+        rule.setOverscrollContentAndReturnViewConfig(
+            scrollableState = scrollableState,
+            overscrollEffect = controller
+        )
+
+        rule.runOnIdle {
+            // we passed isContentScrolls = 1, so initial draw must occur
+            assertThat(controller.drawCallsCount).isEqualTo(1)
+        }
+
+        rule.onNodeWithTag(boxTag).assertExists()
+
+        rule.onNodeWithTag(boxTag).performTouchInput {
+            swipeWithVelocity(
+                center,
+                Offset(centerX + 10800, centerY),
+                endVelocity = 30000f
+            )
+        }
+
+        rule.runOnIdle {
+            with(controller) {
+                // presented on consume pre scroll
+                assertSingleAxisValue(preScrollDelta.x, preScrollDelta.y)
+
+                // presented on consume post scroll
+                assertSingleAxisValue(lastOverscrollDelta.x, lastOverscrollDelta.y)
+                assertSingleAxisValue(lastInitialDragDelta.x, lastInitialDragDelta.y)
+
+                // presented on pre fling
+                assertSingleAxisValue(preFlingVelocity.x, preFlingVelocity.y)
+
+                // presented on post fling
+                assertSingleAxisValue(lastVelocity.x, lastVelocity.y)
+            }
+        }
+    }
+
+    @Test
+    fun verticalOverscrollEnabled_verifyOverscrollReceivedSingleAxisValues() {
+        val controller = TestOverscrollEffect()
+        val scrollableState = ScrollableState { 0f }
+        rule.setOverscrollContentAndReturnViewConfig(
+            scrollableState = scrollableState,
+            overscrollEffect = controller,
+            orientation = Orientation.Vertical
+        )
+
+        rule.runOnIdle {
+            // we passed isContentScrolls = 1, so initial draw must occur
+            assertThat(controller.drawCallsCount).isEqualTo(1)
+        }
+
+        rule.onNodeWithTag(boxTag).assertExists()
+
+        rule.onNodeWithTag(boxTag).performTouchInput {
+            swipeWithVelocity(
+                center,
+                Offset(centerX, centerY + 10800),
+                endVelocity = 30000f
+            )
+        }
+
+        rule.runOnIdle {
+            with(controller) {
+                // presented on consume pre scroll
+                assertSingleAxisValue(preScrollDelta.y, preScrollDelta.x)
+
+                // presented on consume post scroll
+                assertSingleAxisValue(lastOverscrollDelta.y, lastOverscrollDelta.x)
+                assertSingleAxisValue(lastInitialDragDelta.y, lastInitialDragDelta.x)
+
+                // presented on pre fling
+                assertSingleAxisValue(preFlingVelocity.y, preFlingVelocity.x)
+
+                // presented on post fling
+                assertSingleAxisValue(lastVelocity.y, lastVelocity.x)
+            }
+        }
+    }
+
+    @Test
+    fun verticalOverscrollEnabled_notTriggered_verifyCrossAxisIsCorrectlyPropagated() {
+        val controller = TestOverscrollEffect()
+        val inspectableConnection = InspectableConnection()
+        rule.setOverscrollContentAndReturnViewConfig(
+            scrollableState = ScrollableState { 0f },
+            overscrollEffect = controller,
+            orientation = Orientation.Vertical,
+            inspectableConnection = inspectableConnection
+        )
+
+        rule.onNodeWithTag(boxTag).assertExists()
+
+        rule.onNodeWithTag(boxTag).performTouchInput {
+            down(center)
+            moveBy(Offset(100f, 100f))
+            up()
+        }
+
+        rule.runOnIdle {
+            assertThat(inspectableConnection.preScrollOffset.x).isEqualTo(100f)
+        }
+    }
+
+    @Test
+    fun horizontalOverscrollEnabled_notTriggered_verifyCrossAxisIsCorrectlyPropagated() {
+        val controller = TestOverscrollEffect()
+        val inspectableConnection = InspectableConnection()
+        rule.setOverscrollContentAndReturnViewConfig(
+            scrollableState = ScrollableState { 0f },
+            overscrollEffect = controller,
+            orientation = Orientation.Horizontal,
+            inspectableConnection = inspectableConnection
+        )
+
+        rule.onNodeWithTag(boxTag).assertExists()
+
+        rule.onNodeWithTag(boxTag).performTouchInput {
+            down(center)
+            moveBy(Offset(100f, 100f))
+            up()
+        }
+
+        rule.runOnIdle {
+            assertThat(inspectableConnection.preScrollOffset.y).isEqualTo(100f)
+        }
+    }
+
+    private fun assertSingleAxisValue(mainAxis: Float, crossAxis: Float) {
+        assertThat(abs(mainAxis)).isGreaterThan(0)
+        assertThat(crossAxis).isEqualTo(0)
+    }
+
     class TestOverscrollEffect(
         private val consumePreCycles: Boolean = false,
         var animationRunning: Boolean = false
@@ -592,12 +732,14 @@
     scrollableState: ScrollableState,
     overscrollEffect: OverscrollEffect,
     flingBehavior: FlingBehavior? = null,
-    reverseDirection: Boolean = false
+    reverseDirection: Boolean = false,
+    orientation: Orientation = Orientation.Horizontal,
+    inspectableConnection: NestedScrollConnection = NoOpConnection
 ): ViewConfiguration {
     var viewConfiguration: ViewConfiguration? = null
     setContent {
         viewConfiguration = LocalViewConfiguration.current
-        Box {
+        Box(Modifier.nestedScroll(inspectableConnection)) {
             Box(
                 Modifier
                     .testTag("box")
@@ -605,7 +747,7 @@
                     .overscroll(overscrollEffect)
                     .scrollable(
                         state = scrollableState,
-                        orientation = Orientation.Horizontal,
+                        orientation = orientation,
                         overscrollEffect = overscrollEffect,
                         flingBehavior = flingBehavior ?: ScrollableDefaults.flingBehavior(),
                         reverseDirection = reverseDirection
@@ -626,3 +768,14 @@
         }
     }
 }
+
+private val NoOpConnection = object : NestedScrollConnection {}
+
+private class InspectableConnection : NestedScrollConnection {
+    var preScrollOffset = Offset.Zero
+
+    override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
+        preScrollOffset += available
+        return Offset.Zero
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt
index 628c012..6c40374 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollTest.kt
@@ -15,20 +15,24 @@
  */
 package androidx.compose.foundation
 
-import android.os.Build
 import android.os.Handler
 import android.os.Looper
 import androidx.annotation.RequiresApi
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.Orientation.Horizontal
+import androidx.compose.foundation.gestures.Orientation.Vertical
 import androidx.compose.foundation.gestures.animateScrollBy
 import androidx.compose.foundation.gestures.scrollBy
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
@@ -56,8 +60,8 @@
 import androidx.compose.ui.semantics.SemanticsActions
 import androidx.compose.ui.semantics.SemanticsProperties
 import androidx.compose.ui.semantics.getOrNull
-import androidx.compose.ui.test.TouchInjectionScope
 import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.TouchInjectionScope
 import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.assertIsNotDisplayed
 import androidx.compose.ui.test.captureToImage
@@ -65,9 +69,9 @@
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.onNodeWithText
-import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.test.performScrollTo
 import androidx.compose.ui.test.performSemanticsAction
+import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.test.swipeDown
 import androidx.compose.ui.test.swipeLeft
 import androidx.compose.ui.test.swipeRight
@@ -76,14 +80,17 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.LayoutDirection.Ltr
+import androidx.compose.ui.unit.LayoutDirection.Rtl
 import androidx.compose.ui.unit.dp
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.MediumTest
 import androidx.test.filters.SdkSuppress
 import androidx.testutils.AnimationDurationScaleRule
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
 import org.junit.After
@@ -93,12 +100,27 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
+import org.junit.runners.Parameterized
 
 @MediumTest
-@RunWith(AndroidJUnit4::class)
-class ScrollTest {
+@RunWith(Parameterized::class)
+class ScrollTest(private val config: Config) {
+
+    data class Config(
+        val orientation: Orientation,
+        val layoutDirection: LayoutDirection,
+    )
+
+    companion object {
+        @JvmStatic
+        @Parameterized.Parameters(name = "{0}")
+        fun data(): List<Config> = listOf(
+            // Don't need to check both directions for vertical scrolling.
+            Config(Vertical, Ltr),
+            Config(Horizontal, Ltr),
+            Config(Horizontal, Rtl),
+        )
+    }
 
     @get:Rule
     val rule = createComposeRule()
@@ -143,19 +165,19 @@
 
     @SdkSuppress(minSdkVersion = 26)
     @Test
-    fun verticalScroller_SmallContent() {
-        val height = 40
+    fun smallContent() {
+        val size = 40
 
-        composeVerticalScroller(height = height)
+        composeScroller(mainAxisSize = size)
 
-        validateVerticalScroller(height = height)
+        validateScroller(mainAxis = size)
     }
 
     @Test
-    fun verticalScroller_SmallContent_Unscrollable() {
+    fun smallContent_Unscrollable() {
         val scrollState = ScrollState(initial = 0)
 
-        composeVerticalScroller(scrollState)
+        composeScroller(scrollState)
 
         rule.runOnIdle {
             assertTrue(scrollState.maxValue == 0)
@@ -164,24 +186,24 @@
 
     @SdkSuppress(minSdkVersion = 26)
     @Test
-    fun verticalScroller_LargeContent_NoScroll() {
-        val height = 30
+    fun largeContent_NoScroll() {
+        val size = 30
 
-        composeVerticalScroller(height = height)
+        composeScroller(mainAxisSize = size)
 
-        validateVerticalScroller(height = height)
+        validateScroller(mainAxis = size)
     }
 
     @SdkSuppress(minSdkVersion = 26)
     @Test
-    fun verticalScroller_LargeContent_ScrollToEnd() {
+    fun largeContent_ScrollToEnd() {
         val scrollState = ScrollState(initial = 0)
-        val height = 30
+        val size = 30
         val scrollDistance = 10
 
-        composeVerticalScroller(scrollState, height = height)
+        composeScroller(scrollState, mainAxisSize = size)
 
-        validateVerticalScroller(height = height)
+        validateScroller(mainAxis = size)
 
         rule.waitForIdle()
         assertEquals(scrollDistance, scrollState.maxValue)
@@ -189,187 +211,41 @@
             scrollState.scrollTo(scrollDistance)
         }
 
-        validateVerticalScroller(offset = scrollDistance, height = height)
+        validateScroller(offset = scrollDistance, mainAxis = size)
     }
 
     @SdkSuppress(minSdkVersion = 26)
     @Test
-    fun verticalScroller_Reversed() {
+    fun reversed() {
         val scrollState = ScrollState(initial = 0)
-        val height = 30
-        val expectedOffset = defaultCellSize * colors.size - height
+        val size = 30
+        val expectedOffset = defaultCellSize * colors.size - size
 
-        composeVerticalScroller(scrollState, height = height, isReversed = true)
+        composeScroller(scrollState, mainAxisSize = size, isReversed = true)
 
-        validateVerticalScroller(offset = expectedOffset, height = height)
+        validateScroller(offset = expectedOffset, mainAxis = size)
     }
 
     @SdkSuppress(minSdkVersion = 26)
     @Test
-    fun verticalScroller_LargeContent_Reversed_ScrollToEnd() {
+    fun largeContent_Reversed_ScrollToEnd() {
         val scrollState = ScrollState(initial = 0)
-        val height = 20
+        val size = 20
         val scrollDistance = 10
-        val expectedOffset = defaultCellSize * colors.size - height - scrollDistance
+        val expectedOffset = defaultCellSize * colors.size - size - scrollDistance
 
-        composeVerticalScroller(scrollState, height = height, isReversed = true)
+        composeScroller(scrollState, mainAxisSize = size, isReversed = true)
 
         scope.launch {
             scrollState.scrollTo(scrollDistance)
         }
 
-        validateVerticalScroller(offset = expectedOffset, height = height)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_SmallContent() {
-        val width = 40
-
-        composeHorizontalScroller(width = width)
-
-        validateHorizontalScroller(width = width)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_rtl_SmallContent() {
-        val width = 40
-
-        composeHorizontalScroller(width = width, isRtl = true)
-
-        validateHorizontalScroller(width = width, checkInRtl = true)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_LargeContent_NoScroll() {
-        val width = 30
-
-        composeHorizontalScroller(width = width)
-
-        validateHorizontalScroller(width = width)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_rtl_LargeContent_NoScroll() {
-        val width = 30
-
-        composeHorizontalScroller(width = width, isRtl = true)
-
-        validateHorizontalScroller(width = width, checkInRtl = true)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_LargeContent_ScrollToEnd() {
-        val width = 30
-        val scrollDistance = 10
-
-        val scrollState = ScrollState(initial = 0)
-
-        composeHorizontalScroller(scrollState, width = width)
-
-        validateHorizontalScroller(width = width)
-
-        rule.waitForIdle()
-        assertEquals(scrollDistance, scrollState.maxValue)
-        scope.launch {
-            scrollState.scrollTo(scrollDistance)
-        }
-
-        validateHorizontalScroller(offset = scrollDistance, width = width)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_rtl_LargeContent_ScrollToEnd() {
-        val width = 30
-        val scrollDistance = 10
-
-        val scrollState = ScrollState(initial = 0)
-
-        composeHorizontalScroller(scrollState, width = width, isRtl = true)
-
-        validateHorizontalScroller(width = width, checkInRtl = true)
-
-        rule.waitForIdle()
-        assertEquals(scrollDistance, scrollState.maxValue)
-        scope.launch {
-            scrollState.scrollTo(scrollDistance)
-        }
-
-        validateHorizontalScroller(offset = scrollDistance, width = width, checkInRtl = true)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_reversed() {
-        val scrollState = ScrollState(initial = 0)
-        val width = 30
-        val expectedOffset = defaultCellSize * colors.size - width
-
-        composeHorizontalScroller(scrollState, width = width, isReversed = true)
-
-        validateHorizontalScroller(offset = expectedOffset, width = width)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_rtl_reversed() {
-        val scrollState = ScrollState(initial = 0)
-        val width = 30
-        val expectedOffset = defaultCellSize * colors.size - width
-
-        composeHorizontalScroller(scrollState, width = width, isReversed = true, isRtl = true)
-
-        validateHorizontalScroller(offset = expectedOffset, width = width, checkInRtl = true)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_LargeContent_Reversed_ScrollToEnd() {
-        val width = 30
-        val scrollDistance = 10
-
-        val scrollState = ScrollState(initial = 0)
-
-        val expectedOffset = defaultCellSize * colors.size - width - scrollDistance
-
-        composeHorizontalScroller(scrollState, width = width, isReversed = true)
-
-        rule.waitForIdle()
-        scope.launch {
-            scrollState.scrollTo(scrollDistance)
-        }
-
-        validateHorizontalScroller(offset = expectedOffset, width = width)
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    fun horizontalScroller_rtl_LargeContent_Reversed_ScrollToEnd() {
-        val width = 30
-        val scrollDistance = 10
-
-        val scrollState = ScrollState(initial = 0)
-
-        val expectedOffset = defaultCellSize * colors.size - width - scrollDistance
-
-        composeHorizontalScroller(scrollState, width = width, isReversed = true, isRtl = true)
-
-        rule.waitForIdle()
-        scope.launch {
-            scrollState.scrollTo(scrollDistance)
-        }
-
-        validateHorizontalScroller(offset = expectedOffset, width = width, checkInRtl = true)
+        validateScroller(offset = expectedOffset, mainAxis = size)
     }
 
     @Test
-    fun verticalScroller_scrollTo_scrollForward() {
-        createScrollableContent(isVertical = true)
+    fun scrollTo_scrollForward() {
+        createScrollableContent()
 
         rule.onNodeWithText("50")
             .assertIsNotDisplayed()
@@ -378,8 +254,8 @@
     }
 
     @Test
-    fun horizontalScroller_scrollTo_scrollForward() {
-        createScrollableContent(isVertical = false)
+    fun reversed_scrollTo_scrollForward() {
+        createScrollableContent(isReversed = true)
 
         rule.onNodeWithText("50")
             .assertIsNotDisplayed()
@@ -388,61 +264,8 @@
     }
 
     @Test
-    fun horizontalScroller_rtl_scrollTo_scrollForward() {
-        createScrollableContent(isVertical = false, isRtl = true)
-
-        rule.onNodeWithText("50")
-            .assertIsNotDisplayed()
-            .performScrollTo()
-            .assertIsDisplayed()
-    }
-
-    @Test
-    fun verticalScroller_reversed_scrollTo_scrollForward() {
-        createScrollableContent(
-            isVertical = true,
-            scrollState = ScrollState(initial = 0),
-            isReversed = true
-        )
-
-        rule.onNodeWithText("50")
-            .assertIsNotDisplayed()
-            .performScrollTo()
-            .assertIsDisplayed()
-    }
-
-    @Test
-    fun horizontalScroller_reversed_scrollTo_scrollForward() {
-        createScrollableContent(
-            isVertical = false,
-            scrollState = ScrollState(initial = 0),
-            isReversed = true
-        )
-
-        rule.onNodeWithText("50")
-            .assertIsNotDisplayed()
-            .performScrollTo()
-            .assertIsDisplayed()
-    }
-
-    @Test
-    fun verticalScroller_scrollTo_scrollBack() {
-        createScrollableContent(isVertical = true)
-
-        rule.onNodeWithText("50")
-            .assertIsNotDisplayed()
-            .performScrollTo()
-            .assertIsDisplayed()
-
-        rule.onNodeWithText("20")
-            .assertIsNotDisplayed()
-            .performScrollTo()
-            .assertIsDisplayed()
-    }
-
-    @Test
-    fun horizontalScroller_scrollTo_scrollBack() {
-        createScrollableContent(isVertical = false)
+    fun scrollTo_scrollBack() {
+        createScrollableContent()
 
         rule.onNodeWithText("50")
             .assertIsNotDisplayed()
@@ -457,24 +280,12 @@
 
     @Test
     @LargeTest
-    fun verticalScroller_swipeUp_swipeDown() {
-        swipeScrollerAndBack(true, TouchInjectionScope::swipeUp, TouchInjectionScope::swipeDown)
-    }
-
-    @Test
-    @LargeTest
-    fun horizontalScroller_swipeLeft_swipeRight() {
-        swipeScrollerAndBack(false, TouchInjectionScope::swipeLeft, TouchInjectionScope::swipeRight)
-    }
-
-    @Test
-    @LargeTest
-    fun horizontalScroller_rtl_swipeLeft_swipeRight() {
+    fun swipeForward_swipeBackward() {
         swipeScrollerAndBack(
-            false,
-            TouchInjectionScope::swipeRight,
-            TouchInjectionScope::swipeLeft,
-            isRtl = true
+            isVertical = config.orientation == Vertical,
+            isRtl = config.layoutDirection == Rtl,
+            firstSwipe = { configAwareSwipe(forward = true) },
+            secondSwipe = { configAwareSwipe(forward = false) }
         )
     }
 
@@ -496,7 +307,10 @@
             rule.waitForIdle()
         }
 
-        createScrollableContent(isVertical = true, scrollState = scrollState)
+        createScrollableContent(
+            isVertical = config.orientation == Vertical,
+            scrollState = scrollState
+        )
 
         rule.waitForIdle()
         assertThat(scrollState.value).isEqualTo(0)
@@ -519,24 +333,14 @@
     }
 
     @Test
-    fun verticalScroller_LargeContent_coerceWhenMaxChanges() {
+    fun largeContent_coerceWhenMaxChanges() {
         val scrollState = ScrollState(initial = 0)
         val itemCount = mutableStateOf(100)
-        rule.setContent {
-            ExtractCoroutineScope()
-            Box {
-                Column(
-                    Modifier
-                        .size(100.dp)
-                        .testTag(scrollerTag)
-                        .verticalScroll(scrollState)
-                ) {
-                    for (i in 0..itemCount.value) {
-                        BasicText(i.toString())
-                    }
-                }
-            }
-        }
+
+        createScrollableContent(
+            scrollState = scrollState,
+            itemCount = { itemCount.value }
+        )
 
         rule.waitForIdle()
         assertThat(scrollState.value).isEqualTo(0)
@@ -573,7 +377,7 @@
             rule.waitForIdle()
         }
 
-        createScrollableContent(isVertical = true, scrollState = scrollState)
+        createScrollableContent(scrollState = scrollState)
 
         rule.waitForIdle()
         assertThat(scrollState.value).isEqualTo(0)
@@ -601,13 +405,15 @@
         rule.mainClock.autoAdvance = false
         val scrollState = ScrollState(initial = 0)
 
-        createScrollableContent(isVertical = true, scrollState = scrollState)
+        createScrollableContent(scrollState = scrollState)
 
         assertThat(scrollState.value).isEqualTo(0)
         assertThat(scrollState.isScrollInProgress).isEqualTo(false)
 
         rule.onNodeWithTag(scrollerTag)
-            .performTouchInput { swipeUp() }
+            .performTouchInput {
+                configAwareSwipe()
+            }
 
         assertThat(scrollState.isScrollInProgress).isEqualTo(true)
         val scrollAtFlingStart = scrollState.value
@@ -635,9 +441,23 @@
             ExtractCoroutineScope()
             val actualState = rememberScrollState()
             SideEffect { scrollState = actualState }
-            Column(Modifier.verticalScroll(actualState)) {
+            val content = @Composable {
                 repeat(50) {
-                    Box(Modifier.height(100.dp))
+                    Box(Modifier.size(100.dp))
+                }
+            }
+            when (config.orientation) {
+                Vertical -> {
+                    Column(Modifier.verticalScroll(actualState)) {
+                        content()
+                    }
+                }
+                Horizontal -> {
+                    CompositionLocalProvider(LocalLayoutDirection provides config.layoutDirection) {
+                        Row(Modifier.horizontalScroll(actualState)) {
+                            content()
+                        }
+                    }
                 }
             }
         }
@@ -656,54 +476,22 @@
         }
     }
 
-    private fun swipeScrollerAndBack(
-        isVertical: Boolean,
-        firstSwipe: TouchInjectionScope.() -> Unit,
-        secondSwipe: TouchInjectionScope.() -> Unit,
-        isRtl: Boolean = false
-    ) {
-        rule.mainClock.autoAdvance = false
-        val scrollState = ScrollState(initial = 0)
-
-        createScrollableContent(isVertical, scrollState = scrollState, isRtl = isRtl)
-
-        assertThat(scrollState.value).isEqualTo(0)
-
-        rule.onNodeWithTag(scrollerTag)
-            .performTouchInput { firstSwipe() }
-
-        rule.mainClock.advanceTimeBy(5000)
-
-        rule.onNodeWithTag(scrollerTag)
-            .awaitScrollAnimation(scrollState)
-
-        val scrolledValue = scrollState.value
-        assertThat(scrolledValue).isGreaterThan(0)
-
-        rule.onNodeWithTag(scrollerTag)
-            .performTouchInput { secondSwipe() }
-
-        rule.mainClock.advanceTimeBy(5000)
-
-        rule.onNodeWithTag(scrollerTag)
-            .awaitScrollAnimation(scrollState)
-
-        assertThat(scrollState.value).isLessThan(scrolledValue)
-    }
-
     @Test
     fun scroller_semanticsScroll_isAnimated() {
         rule.mainClock.autoAdvance = false
         val scrollState = ScrollState(initial = 0)
 
-        createScrollableContent(isVertical = true, scrollState = scrollState)
+        createScrollableContent(scrollState = scrollState)
 
         rule.waitForIdle()
         assertThat(scrollState.value).isEqualTo(0)
         assertThat(scrollState.maxValue).isGreaterThan(100) // If this fails, just add more items
 
         rule.onNodeWithTag(scrollerTag).performSemanticsAction(SemanticsActions.ScrollBy) {
-            it(0f, 100f)
+            when (config.orientation) {
+                Vertical -> it(0f, 100f)
+                Horizontal -> it(100f, 0f)
+            }
         }
 
         // We haven't advanced time yet, make sure it's still zero
@@ -725,13 +513,20 @@
     fun scroller_touchInputEnabled_shouldHaveSemanticsInfo() {
         val scrollState = ScrollState(initial = 0)
         val scrollNode = rule.onNodeWithTag(scrollerTag)
-        createScrollableContent(isVertical = true, scrollState = scrollState)
+        createScrollableContent(scrollState = scrollState)
         val yScrollState = scrollNode
             .fetchSemanticsNode()
             .config
-            .getOrNull(SemanticsProperties.VerticalScrollAxisRange)
+            .getOrNull(
+                when (config.orientation) {
+                    Vertical -> SemanticsProperties.VerticalScrollAxisRange
+                    Horizontal -> SemanticsProperties.HorizontalScrollAxisRange
+                }
+            )
 
-        scrollNode.performTouchInput { swipeUp() }
+        scrollNode.performTouchInput {
+            configAwareSwipe()
+        }
 
         assertThat(yScrollState?.value?.invoke()).isEqualTo(scrollState.value)
     }
@@ -741,18 +536,24 @@
         val scrollState = ScrollState(initial = 0)
         val scrollNode = rule.onNodeWithTag(scrollerTag)
         createScrollableContent(
-            isVertical = true,
             scrollState = scrollState,
             touchInputEnabled = false
         )
-        val yScrollState = scrollNode
+        val scrollSemantics = scrollNode
             .fetchSemanticsNode()
             .config
-            .getOrNull(SemanticsProperties.VerticalScrollAxisRange)
+            .getOrNull(
+                when (config.orientation) {
+                    Vertical -> SemanticsProperties.VerticalScrollAxisRange
+                    Horizontal -> SemanticsProperties.HorizontalScrollAxisRange
+                }
+            )
 
-        scrollNode.performTouchInput { swipeUp() }
+        scrollNode.performTouchInput {
+            configAwareSwipe()
+        }
 
-        assertThat(yScrollState?.value?.invoke()).isEqualTo(scrollState.value)
+        assertThat(scrollSemantics?.value?.invoke()).isEqualTo(scrollState.value)
     }
 
     @Test
@@ -765,25 +566,229 @@
         rule.setContent {
             Box {
                 Box(Modifier.size(containerSize, containerSize)) {
-                    Column(
-                        Modifier
-                            .testTag(scrollerTag)
-                            .verticalScroll(state = scrollState)
-                    ) {
-                        Box(Modifier.height(contentSize).fillMaxWidth())
+                    when (config.orientation) {
+                        Vertical -> {
+                            Column(
+                                Modifier
+                                    .testTag(scrollerTag)
+                                    .verticalScroll(state = scrollState)
+                            ) {
+                                Box(
+                                    Modifier
+                                        .height(contentSize)
+                                        .fillMaxWidth()
+                                )
+                            }
+                        }
+                        Horizontal -> {
+                            CompositionLocalProvider(
+                                LocalLayoutDirection provides config.layoutDirection
+                            ) {
+                                Row(
+                                    Modifier
+                                        .testTag(scrollerTag)
+                                        .horizontalScroll(state = scrollState)
+                                ) {
+                                    Box(
+                                        Modifier
+                                            .width(contentSize)
+                                            .fillMaxHeight()
+                                    )
+                                }
+                            }
+                        }
                     }
                 }
             }
         }
 
         rule.onNodeWithTag(scrollerTag)
-            .performTouchInput { swipeUp() }
+            .performTouchInput {
+                configAwareSwipe()
+            }
 
         rule.runOnIdle {
             assertThat(scrollState.value).isEqualTo(10)
         }
     }
 
+    @Test
+    fun testInspectorValue() {
+        val state = ScrollState(initial = 0)
+        rule.setContent {
+            val modifier = when (config.orientation) {
+                Vertical -> Modifier.verticalScroll(state)
+                Horizontal -> Modifier.horizontalScroll(state)
+            } as InspectableValue
+            assertThat(modifier.nameFallback).isEqualTo("scroll")
+            assertThat(modifier.valueOverride).isNull()
+            assertThat(modifier.inspectableElements.map { it.name }.asIterable()).containsExactly(
+                "state",
+                "reverseScrolling",
+                "flingBehavior",
+                "isScrollable",
+                "isVertical"
+            )
+        }
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test
+    fun doesNotClipOverdraw() {
+        rule.setContent {
+            val scrollState = rememberScrollState(20)
+            Box(
+                Modifier
+                    .size(60.dp)
+                    .testTag("container")
+                    .background(Color.Gray)
+            ) {
+                val content = @Composable {
+                    repeat(4) {
+                        Box(
+                            Modifier
+                                .size(20.dp)
+                                .drawOutsideOfBounds()
+                        )
+                    }
+                }
+                when (config.orientation) {
+                    Vertical -> {
+                        Column(
+                            Modifier
+                                .padding(20.dp)
+                                .fillMaxSize()
+                                .verticalScroll(scrollState)
+                        ) {
+                            content()
+                        }
+                    }
+                    Horizontal -> {
+                        CompositionLocalProvider(
+                            LocalLayoutDirection provides config.layoutDirection
+                        ) {
+                            Row(
+                                Modifier
+                                    .padding(20.dp)
+                                    .fillMaxSize()
+                                    .horizontalScroll(scrollState)
+                            ) {
+                                content()
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        val (horizontalPadding, verticalPadding) = when (config.orientation) {
+            Vertical -> Pair(0.dp, 20.dp)
+            Horizontal -> Pair(20.dp, 0.dp)
+        }
+
+        rule.onNodeWithTag("container")
+            .captureToImage()
+            .assertShape(
+                density = rule.density,
+                shape = RectangleShape,
+                shapeColor = Color.Red,
+                backgroundColor = Color.Gray,
+                horizontalPadding = horizontalPadding,
+                verticalPadding = verticalPadding
+            )
+    }
+
+    @Test
+    fun intrinsicMeasurements() = with(rule.density) {
+        rule.setContent {
+            Layout(
+                content = {
+                    CompositionLocalProvider(LocalLayoutDirection provides config.layoutDirection) {
+                        Layout(
+                            content = {},
+                            modifier = when (config.orientation) {
+                                Vertical -> Modifier.verticalScroll(rememberScrollState())
+                                Horizontal -> Modifier.horizontalScroll(rememberScrollState())
+                            },
+                            object : MeasurePolicy {
+                                override fun MeasureScope.measure(
+                                    measurables: List<Measurable>,
+                                    constraints: Constraints,
+                                ) = layout(0, 0) {}
+
+                                override fun IntrinsicMeasureScope.minIntrinsicWidth(
+                                    measurables: List<IntrinsicMeasurable>,
+                                    height: Int,
+                                ) = 10.dp.roundToPx()
+
+                                override fun IntrinsicMeasureScope.minIntrinsicHeight(
+                                    measurables: List<IntrinsicMeasurable>,
+                                    width: Int,
+                                ) = 20.dp.roundToPx()
+
+                                override fun IntrinsicMeasureScope.maxIntrinsicWidth(
+                                    measurables: List<IntrinsicMeasurable>,
+                                    height: Int,
+                                ) = 30.dp.roundToPx()
+
+                                override fun IntrinsicMeasureScope.maxIntrinsicHeight(
+                                    measurables: List<IntrinsicMeasurable>,
+                                    width: Int,
+                                ) = 40.dp.roundToPx()
+                            }
+                        )
+                    }
+                }
+            ) { measurables, _ ->
+                val measurable = measurables.first()
+                assertEquals(10.dp.roundToPx(), measurable.minIntrinsicWidth(Constraints.Infinity))
+                assertEquals(20.dp.roundToPx(), measurable.minIntrinsicHeight(Constraints.Infinity))
+                assertEquals(30.dp.roundToPx(), measurable.maxIntrinsicWidth(Constraints.Infinity))
+                assertEquals(40.dp.roundToPx(), measurable.maxIntrinsicHeight(Constraints.Infinity))
+                layout(0, 0) {}
+            }
+        }
+        rule.waitForIdle()
+    }
+
+    /**
+     * Swipes forward (up/left) or backward given the current orientation and layout direction
+     * of the test config.
+     */
+    private fun TouchInjectionScope.configAwareSwipe(forward: Boolean = true) =
+        when (config.orientation) {
+            Vertical -> if (forward) swipeUp() else swipeDown()
+            Horizontal -> when (config.layoutDirection) {
+                Ltr -> if (forward) swipeLeft() else swipeRight()
+                Rtl -> if (forward) swipeRight() else swipeLeft()
+            }
+        }
+
+    private fun composeScroller(
+        scrollState: ScrollState? = null,
+        isReversed: Boolean = false,
+        mainAxisSize: Int = defaultMainAxisSize,
+        crossAxisSize: Int = defaultCrossAxisSize,
+        cellSize: Int = defaultCellSize
+    ) {
+        when (config.orientation) {
+            Vertical -> composeVerticalScroller(
+                scrollState = scrollState,
+                isReversed = isReversed,
+                width = crossAxisSize,
+                height = mainAxisSize,
+                rowHeight = cellSize
+            )
+            Horizontal -> composeHorizontalScroller(
+                scrollState = scrollState,
+                isReversed = isReversed,
+                width = mainAxisSize,
+                height = crossAxisSize,
+                isRtl = config.layoutDirection == Rtl
+            )
+        }
+    }
+
     private fun composeVerticalScroller(
         scrollState: ScrollState? = null,
         isReversed: Boolean = false,
@@ -831,7 +836,7 @@
         with(rule.density) {
             rule.setContent {
                 ExtractCoroutineScope()
-                val direction = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
+                val direction = if (isRtl) Rtl else Ltr
                 CompositionLocalProvider(LocalLayoutDirection provides direction) {
                     Box {
                         Row(
@@ -858,6 +863,29 @@
     }
 
     @RequiresApi(api = 26)
+    private fun validateScroller(
+        offset: Int = 0,
+        mainAxis: Int = 40,
+        crossAxis: Int = 45,
+        cellSize: Int = 5
+    ) {
+        when (config.orientation) {
+            Vertical -> validateVerticalScroller(
+                offset = offset,
+                width = crossAxis,
+                height = mainAxis,
+                rowHeight = cellSize
+            )
+            Horizontal -> validateHorizontalScroller(
+                offset = offset,
+                width = mainAxis,
+                height = crossAxis,
+                checkInRtl = config.layoutDirection == Rtl
+            )
+        }
+    }
+
+    @RequiresApi(api = 26)
     private fun validateVerticalScroller(
         offset: Int = 0,
         width: Int = 45,
@@ -890,26 +918,28 @@
     }
 
     private fun createScrollableContent(
-        isVertical: Boolean,
-        itemCount: Int = 100,
+        isVertical: Boolean = config.orientation == Vertical,
+        itemCount: () -> Int = { 100 },
         width: Dp = 100.dp,
         height: Dp = 100.dp,
         isReversed: Boolean = false,
         scrollState: ScrollState? = null,
-        isRtl: Boolean = false,
+        isRtl: Boolean = config.layoutDirection == Rtl,
         touchInputEnabled: Boolean = true
     ) {
         val resolvedState = scrollState ?: ScrollState(initial = 0)
         rule.setContent {
             ExtractCoroutineScope()
             val content = @Composable {
-                repeat(itemCount) {
+                repeat(itemCount()) {
                     BasicText(text = "$it")
                 }
             }
             Box {
                 Box(
-                    Modifier.size(width, height).background(Color.White)
+                    Modifier
+                        .size(width, height)
+                        .background(Color.White)
                 ) {
                     if (isVertical) {
                         Column(
@@ -924,10 +954,11 @@
                             content()
                         }
                     } else {
-                        val direction = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
+                        val direction = if (isRtl) Rtl else Ltr
                         CompositionLocalProvider(LocalLayoutDirection provides direction) {
                             Row(
-                                Modifier.testTag(scrollerTag)
+                                Modifier
+                                    .testTag(scrollerTag)
                                     .horizontalScroll(
                                         resolvedState,
                                         enabled = touchInputEnabled,
@@ -963,130 +994,39 @@
         return this
     }
 
-    @Test
-    fun testInspectorValue() {
-        val state = ScrollState(initial = 0)
-        rule.setContent {
-            val modifier = Modifier.verticalScroll(state) as InspectableValue
-            assertThat(modifier.nameFallback).isEqualTo("scroll")
-            assertThat(modifier.valueOverride).isNull()
-            assertThat(modifier.inspectableElements.map { it.name }.asIterable()).containsExactly(
-                "state",
-                "reverseScrolling",
-                "flingBehavior",
-                "isScrollable",
-                "isVertical"
-            )
-        }
-    }
+    private fun swipeScrollerAndBack(
+        isVertical: Boolean = config.orientation == Vertical,
+        firstSwipe: TouchInjectionScope.() -> Unit,
+        secondSwipe: TouchInjectionScope.() -> Unit,
+        isRtl: Boolean = config.layoutDirection == Rtl
+    ) {
+        rule.mainClock.autoAdvance = false
+        val scrollState = ScrollState(initial = 0)
 
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    @Test
-    fun horizontalScroller_doesNotClipVerticalOverdraw() {
-        rule.setContent {
-            Box(Modifier.size(60.dp).testTag("container").background(Color.Gray)) {
-                Row(
-                    Modifier
-                        .padding(20.dp)
-                        .fillMaxSize()
-                        .horizontalScroll(rememberScrollState(20))
-                ) {
-                    repeat(4) {
-                        Box(Modifier.size(20.dp).drawOutsideOfBounds())
-                    }
-                }
-            }
-        }
+        createScrollableContent(isVertical, scrollState = scrollState, isRtl = isRtl)
 
-        rule.onNodeWithTag("container")
-            .captureToImage()
-            .assertShape(
-                density = rule.density,
-                shape = RectangleShape,
-                shapeColor = Color.Red,
-                backgroundColor = Color.Gray,
-                horizontalPadding = 20.dp,
-                verticalPadding = 0.dp
-            )
-    }
+        assertThat(scrollState.value).isEqualTo(0)
 
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    @Test
-    fun verticalScroller_doesNotClipHorizontalOverdraw() {
-        rule.setContent {
-            Box(Modifier.size(60.dp).testTag("container").background(Color.Gray)) {
-                Column(
-                    Modifier
-                        .padding(20.dp)
-                        .fillMaxSize()
-                        .verticalScroll(rememberScrollState(20))
-                ) {
-                    repeat(4) {
-                        Box(Modifier.size(20.dp).drawOutsideOfBounds())
-                    }
-                }
-            }
-        }
+        rule.onNodeWithTag(scrollerTag)
+            .performTouchInput { firstSwipe() }
 
-        rule.onNodeWithTag("container")
-            .captureToImage()
-            .assertShape(
-                density = rule.density,
-                shape = RectangleShape,
-                shapeColor = Color.Red,
-                backgroundColor = Color.Gray,
-                horizontalPadding = 0.dp,
-                verticalPadding = 20.dp
-            )
-    }
+        rule.mainClock.advanceTimeBy(5000)
 
-    @Test
-    fun intrinsicMeasurements() = with(rule.density) {
-        rule.setContent {
-            Layout(
-                content = {
-                    Layout(
-                        {},
-                        Modifier.verticalScroll(rememberScrollState())
-                            .horizontalScroll(rememberScrollState()),
-                        object : MeasurePolicy {
-                            override fun MeasureScope.measure(
-                                measurables: List<Measurable>,
-                                constraints: Constraints,
-                            ) = layout(0, 0) {}
+        rule.onNodeWithTag(scrollerTag)
+            .awaitScrollAnimation(scrollState)
 
-                            override fun IntrinsicMeasureScope.minIntrinsicWidth(
-                                measurables: List<IntrinsicMeasurable>,
-                                height: Int,
-                            ) = 10.dp.roundToPx()
+        val scrolledValue = scrollState.value
+        assertThat(scrolledValue).isGreaterThan(0)
 
-                            override fun IntrinsicMeasureScope.minIntrinsicHeight(
-                                measurables: List<IntrinsicMeasurable>,
-                                width: Int,
-                            ) = 20.dp.roundToPx()
+        rule.onNodeWithTag(scrollerTag)
+            .performTouchInput { secondSwipe() }
 
-                            override fun IntrinsicMeasureScope.maxIntrinsicWidth(
-                                measurables: List<IntrinsicMeasurable>,
-                                height: Int,
-                            ) = 30.dp.roundToPx()
+        rule.mainClock.advanceTimeBy(5000)
 
-                            override fun IntrinsicMeasureScope.maxIntrinsicHeight(
-                                measurables: List<IntrinsicMeasurable>,
-                                width: Int,
-                            ) = 40.dp.roundToPx()
-                        }
-                    )
-                }
-            ) { measurables, _ ->
-                val measurable = measurables.first()
-                assertEquals(10.dp.roundToPx(), measurable.minIntrinsicWidth(Constraints.Infinity))
-                assertEquals(20.dp.roundToPx(), measurable.minIntrinsicHeight(Constraints.Infinity))
-                assertEquals(30.dp.roundToPx(), measurable.maxIntrinsicWidth(Constraints.Infinity))
-                assertEquals(40.dp.roundToPx(), measurable.maxIntrinsicHeight(Constraints.Infinity))
-                layout(0, 0) {}
-            }
-        }
-        rule.waitForIdle()
+        rule.onNodeWithTag(scrollerTag)
+            .awaitScrollAnimation(scrollState)
+
+        assertThat(scrollState.value).isLessThan(scrolledValue)
     }
 
     private fun Modifier.drawOutsideOfBounds() = drawBehind {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
index 44589d7..49053f2 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/ScrollableTest.kt
@@ -24,13 +24,20 @@
 import androidx.compose.foundation.gestures.ScrollScope
 import androidx.compose.foundation.gestures.ScrollableState
 import androidx.compose.foundation.gestures.animateScrollBy
+import androidx.compose.foundation.gestures.awaitFirstDown
 import androidx.compose.foundation.gestures.scrollable
 import androidx.compose.foundation.interaction.DragInteraction
 import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.LazyListState
+import androidx.compose.foundation.lazy.rememberLazyListState
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.SideEffect
 import androidx.compose.runtime.currentComposer
@@ -39,6 +46,7 @@
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusDirection
 import androidx.compose.ui.focus.FocusManager
@@ -46,13 +54,19 @@
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.focus.onFocusChanged
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher
 import androidx.compose.ui.input.nestedscroll.NestedScrollSource
 import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.input.pointer.PointerInputScope
+import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.input.pointer.util.VelocityTracker
 import androidx.compose.ui.materialize
 import androidx.compose.ui.modifier.ModifierLocalConsumer
 import androidx.compose.ui.modifier.ModifierLocalReadScope
+import androidx.compose.ui.platform.AbstractComposeView
 import androidx.compose.ui.platform.InspectableValue
 import androidx.compose.ui.platform.LocalFocusManager
 import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
@@ -65,22 +79,37 @@
 import androidx.compose.ui.test.performMouseInput
 import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.test.swipe
+import androidx.compose.ui.test.swipeDown
+import androidx.compose.ui.test.swipeLeft
+import androidx.compose.ui.test.swipeRight
+import androidx.compose.ui.test.swipeUp
 import androidx.compose.ui.test.swipeWithVelocity
 import androidx.compose.ui.unit.Velocity
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastForEach
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.CoordinatesProvider
+import androidx.test.espresso.action.GeneralLocation
+import androidx.test.espresso.action.GeneralSwipeAction
+import androidx.test.espresso.action.Press
+import androidx.test.espresso.action.Swipe
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import kotlin.math.abs
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
+import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.hamcrest.CoreMatchers.allOf
+import org.hamcrest.CoreMatchers.instanceOf
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import kotlin.math.abs
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
@@ -2040,6 +2069,161 @@
         rule.runOnIdle { assertThat(nextItemIsFocused).isTrue() }
     }
 
+    @Test
+    fun verticalScrollable_assertVelocityCalculationIsSimilarInsideOutsideVelocityTracker() {
+        // arrange
+        val tracker = VelocityTracker()
+        var velocity = Velocity.Zero
+        val capturingScrollConnection = object : NestedScrollConnection {
+            override suspend fun onPreFling(available: Velocity): Velocity {
+                velocity += available
+                return Velocity.Zero
+            }
+        }
+        val controller = ScrollableState { _ -> 0f }
+
+        setScrollableContent {
+            Modifier
+                .pointerInput(Unit) {
+                    savePointerInputEvents(tracker, this)
+                }
+                .nestedScroll(capturingScrollConnection)
+                .scrollable(controller, Orientation.Vertical)
+        }
+
+        // act
+        rule.onNodeWithTag(scrollableBoxTag).performTouchInput {
+            swipeUp()
+        }
+
+        // assert
+        rule.runOnIdle {
+            val diff = abs((velocity - tracker.calculateVelocity()).y)
+            assertThat(diff).isLessThan(VelocityTrackerCalculationThreshold)
+        }
+        tracker.resetTracking()
+        velocity = Velocity.Zero
+
+        // act
+        rule.onNodeWithTag(scrollableBoxTag).performTouchInput {
+            swipeDown()
+        }
+
+        // assert
+        rule.runOnIdle {
+            val diff = abs((velocity - tracker.calculateVelocity()).y)
+            assertThat(diff).isLessThan(VelocityTrackerCalculationThreshold)
+        }
+    }
+
+    @Test
+    fun horizontalScrollable_assertVelocityCalculationIsSimilarInsideOutsideVelocityTracker() {
+        // arrange
+        val tracker = VelocityTracker()
+        var velocity = Velocity.Zero
+        val capturingScrollConnection = object : NestedScrollConnection {
+            override suspend fun onPreFling(available: Velocity): Velocity {
+                velocity += available
+                return Velocity.Zero
+            }
+        }
+        val controller = ScrollableState { _ -> 0f }
+
+        setScrollableContent {
+            Modifier
+                .pointerInput(Unit) {
+                    savePointerInputEvents(tracker, this)
+                }
+                .nestedScroll(capturingScrollConnection)
+                .scrollable(controller, Orientation.Horizontal)
+        }
+
+        // act
+        rule.onNodeWithTag(scrollableBoxTag).performTouchInput {
+            swipeLeft()
+        }
+
+        // assert
+        rule.runOnIdle {
+            val diff = abs((velocity - tracker.calculateVelocity()).x)
+            assertThat(diff).isLessThan(VelocityTrackerCalculationThreshold)
+        }
+        tracker.resetTracking()
+        velocity = Velocity.Zero
+
+        // act
+        rule.onNodeWithTag(scrollableBoxTag).performTouchInput {
+            swipeRight()
+        }
+
+        // assert
+        rule.runOnIdle {
+            val diff = abs((velocity - tracker.calculateVelocity()).x)
+            assertThat(diff).isLessThan(VelocityTrackerCalculationThreshold)
+        }
+    }
+
+    @Test
+    fun offsetsScrollable_velocityCalculationShouldConsiderLocalPositions() {
+        // arrange
+        var velocity = Velocity.Zero
+        val fullScreen = mutableStateOf(false)
+        lateinit var scrollState: LazyListState
+        val capturingScrollConnection = object : NestedScrollConnection {
+            override suspend fun onPreFling(available: Velocity): Velocity {
+                velocity += available
+                return Velocity.Zero
+            }
+        }
+        rule.setContent {
+            scrollState = rememberLazyListState()
+            Column(modifier = Modifier.nestedScroll(capturingScrollConnection)) {
+                if (!fullScreen.value) {
+                    Box(
+                        modifier = Modifier
+                            .fillMaxWidth()
+                            .background(Color.Black)
+                            .height(400.dp)
+                    )
+                }
+
+                LazyColumn(state = scrollState) {
+                    items(100) {
+                        Box(
+                            modifier = Modifier
+                                .padding(10.dp)
+                                .background(Color.Red)
+                                .fillMaxWidth()
+                                .height(50.dp)
+                        )
+                    }
+                }
+            }
+        }
+        // act
+        // Register generated velocity with offset
+        composeViewSwipeUp()
+        rule.waitForIdle()
+        val previousVelocity = velocity
+        velocity = Velocity.Zero
+        // Remove offset and restart scroll
+        fullScreen.value = true
+        rule.runOnIdle {
+            runBlocking {
+                scrollState.scrollToItem(0)
+            }
+        }
+        rule.waitForIdle()
+        // Register generated velocity without offset, should be larger as there was more
+        // screen to cover.
+        composeViewSwipeUp()
+
+        // assert
+        rule.runOnIdle {
+            assertThat(abs(previousVelocity.y)).isNotEqualTo(abs(velocity.y))
+        }
+    }
+
     private fun setScrollableContent(scrollableModifierFactory: @Composable () -> Modifier) {
         rule.setContentAndGetScope {
             Box {
@@ -2083,3 +2267,88 @@
 
     override val effectModifier: Modifier get() = Modifier
 }
+
+// Very low tolerance on the difference
+internal val VelocityTrackerCalculationThreshold = 1
+
+@OptIn(ExperimentalComposeUiApi::class)
+internal suspend fun savePointerInputEvents(
+    tracker: VelocityTracker,
+    pointerInputScope: PointerInputScope
+) {
+    with(pointerInputScope) {
+        coroutineScope {
+            awaitPointerEventScope {
+                while (true) {
+                    var event = awaitFirstDown()
+                    tracker.addPosition(event.uptimeMillis, event.position)
+                    while (!event.changedToUpIgnoreConsumed()) {
+                        val currentEvent = awaitPointerEvent().changes
+                            .firstOrNull()
+
+                        if (currentEvent != null && !currentEvent.changedToUpIgnoreConsumed()) {
+                            currentEvent.historical.fastForEach {
+                                tracker.addPosition(it.uptimeMillis, it.position)
+                            }
+                            tracker.addPosition(
+                                currentEvent.uptimeMillis,
+                                currentEvent.position
+                            )
+                            event = currentEvent
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+internal fun composeViewSwipeUp() {
+    onView(allOf(instanceOf(AbstractComposeView::class.java)))
+        .perform(
+            espressoSwipe(
+                GeneralLocation.BOTTOM_CENTER,
+                GeneralLocation.CENTER
+            )
+        )
+}
+
+internal fun composeViewSwipeDown() {
+    onView(allOf(instanceOf(AbstractComposeView::class.java)))
+        .perform(
+            espressoSwipe(
+                GeneralLocation.CENTER,
+                GeneralLocation.BOTTOM_CENTER
+            )
+        )
+}
+
+internal fun composeViewSwipeLeft() {
+    onView(allOf(instanceOf(AbstractComposeView::class.java)))
+        .perform(
+            espressoSwipe(
+                GeneralLocation.CENTER,
+                GeneralLocation.CENTER_LEFT
+            )
+        )
+}
+
+internal fun composeViewSwipeRight() {
+    onView(allOf(instanceOf(AbstractComposeView::class.java)))
+        .perform(
+            espressoSwipe(
+                GeneralLocation.CENTER,
+                GeneralLocation.CENTER_RIGHT
+            )
+        )
+}
+
+private fun espressoSwipe(
+    start: CoordinatesProvider,
+    end: CoordinatesProvider
+): GeneralSwipeAction {
+    return GeneralSwipeAction(
+        Swipe.FAST, start, end,
+        Press.FINGER
+    )
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/BaseLazyListTestWithOrientation.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/BaseLazyListTestWithOrientation.kt
index 1c3c0ae..1919263 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/BaseLazyListTestWithOrientation.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/BaseLazyListTestWithOrientation.kt
@@ -18,6 +18,10 @@
 
 import androidx.compose.animation.core.snap
 import androidx.compose.foundation.AutoTestFrameClock
+import androidx.compose.foundation.composeViewSwipeDown
+import androidx.compose.foundation.composeViewSwipeLeft
+import androidx.compose.foundation.composeViewSwipeRight
+import androidx.compose.foundation.composeViewSwipeUp
 import androidx.compose.foundation.gestures.FlingBehavior
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.gestures.ScrollableDefaults
@@ -180,6 +184,22 @@
         density = rule.density
     )
 
+    fun composeViewSwipeForward() {
+        if (orientation == Orientation.Vertical) {
+            composeViewSwipeUp()
+        } else {
+            composeViewSwipeLeft()
+        }
+    }
+
+    fun composeViewSwipeBackward() {
+        if (orientation == Orientation.Vertical) {
+            composeViewSwipeDown()
+        } else {
+            composeViewSwipeRight()
+        }
+    }
+
     @Composable
     fun LazyColumnOrRow(
         modifier: Modifier = Modifier,
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListTest.kt
index 48a7d4b..b0f7d04 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/list/LazyListTest.kt
@@ -18,6 +18,7 @@
 
 import android.os.Build
 import androidx.compose.foundation.AutoTestFrameClock
+import androidx.compose.foundation.VelocityTrackerCalculationThreshold
 import androidx.compose.foundation.background
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.layout.Box
@@ -26,6 +27,7 @@
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.layout.requiredSize
@@ -36,6 +38,7 @@
 import androidx.compose.foundation.lazy.items
 import androidx.compose.foundation.lazy.itemsIndexed
 import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.savePointerInputEvents
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
@@ -57,6 +60,8 @@
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 import androidx.compose.ui.input.nestedscroll.NestedScrollSource
 import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.input.pointer.util.VelocityTracker
 import androidx.compose.ui.layout.layout
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.SemanticsActions
@@ -83,6 +88,7 @@
 import androidx.compose.ui.test.swipeWithVelocity
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.Velocity
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.zIndex
 import androidx.test.filters.LargeTest
@@ -92,6 +98,7 @@
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import java.util.concurrent.CountDownLatch
+import kotlin.math.abs
 import kotlinx.coroutines.runBlocking
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -1923,6 +1930,58 @@
             .assertStartPositionInRootIsEqualTo(0.dp)
     }
 
+    @Test
+    fun assertVelocityCalculationIsSimilar_witHistoricalValues() {
+        // arrange
+        val tracker = VelocityTracker()
+        var velocity = Velocity.Zero
+        val capturingScrollConnection = object : NestedScrollConnection {
+            override suspend fun onPreFling(available: Velocity): Velocity {
+                velocity += available
+                return Velocity.Zero
+            }
+        }
+        rule.setContent {
+            Box(modifier = Modifier
+                .background(Color.Yellow)
+                .nestedScroll(capturingScrollConnection)
+                .fillMaxWidth()
+                .pointerInput(Unit) {
+                    savePointerInputEvents(tracker, this)
+                }) {
+                LazyColumnOrRow {
+                    items(200) {
+                        Box(modifier = Modifier
+                            .fillMaxWidth()
+                            .height(48.dp)
+                            .padding(8.dp)
+                            .background(Color.Blue))
+                    }
+                }
+            }
+        }
+
+        // act
+        composeViewSwipeForward()
+
+        // assert
+        rule.runOnIdle {
+            val diff = abs((velocity - tracker.calculateVelocity()).y)
+            assertThat(diff).isLessThan(VelocityTrackerCalculationThreshold)
+        }
+        tracker.resetTracking()
+        velocity = Velocity.Zero
+
+        // act
+        composeViewSwipeBackward()
+
+        // assert
+        rule.runOnIdle {
+            val diff = abs((velocity - tracker.calculateVelocity()).y)
+            assertThat(diff).isLessThan(VelocityTrackerCalculationThreshold)
+        }
+    }
+
     // ********************* END OF TESTS *********************
     // Helper functions, etc. live below here
 
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldSelectionContentChangeTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldSelectionContentChangeTest.kt
new file mode 100644
index 0000000..db18624
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldSelectionContentChangeTest.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2021 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.foundation.text
+
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.input.key.NativeKeyEvent
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.semantics.getOrNull
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.longClick
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performKeyPress
+import androidx.compose.ui.test.performTextInputSelection
+import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.text.TextRange
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalTestApi::class)
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class CoreTextFieldSelectionContentChangeTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    private val Tag = "textField"
+
+    private val backspaceKeyDown = KeyEvent(
+        NativeKeyEvent(
+            NativeKeyEvent.ACTION_DOWN,
+            NativeKeyEvent.KEYCODE_DEL
+        )
+    )
+    private val backspaceKeyUp = KeyEvent(
+        NativeKeyEvent(
+            NativeKeyEvent.ACTION_UP,
+            NativeKeyEvent.KEYCODE_DEL
+        )
+    )
+
+    @Test
+    fun whenSelectedTextIsRemoved_SelectionCoerces() {
+        val textFieldValue = mutableStateOf("Hello")
+        rule.setContent {
+            BasicTextField(
+                value = textFieldValue.value,
+                onValueChange = {
+                    textFieldValue.value = it
+                },
+                modifier = Modifier.testTag(Tag).wrapContentSize()
+            )
+        }
+        val textNode = rule.onNodeWithTag(Tag)
+        textNode.performTouchInput { longClick() }
+        textNode.performTextInputSelection(TextRange(0, 4))
+        textFieldValue.value = ""
+
+        rule.waitForIdle()
+        val expected = TextRange(0, 0)
+        val actual = textNode.fetchSemanticsNode().config
+            .getOrNull(SemanticsProperties.TextSelectionRange)
+        assertThat(actual).isEqualTo(expected)
+    }
+
+    @Test
+    fun whenPartiallySelectedTextIsRemoved_SelectionCoercesToEdges() {
+        val textFieldValue = mutableStateOf("Hello World!")
+        rule.setContent {
+            BasicTextField(
+                value = textFieldValue.value,
+                onValueChange = {
+                    textFieldValue.value = it
+                },
+                modifier = Modifier.testTag(Tag).wrapContentSize()
+            )
+        }
+        val textNode = rule.onNodeWithTag(Tag)
+        textNode.performTouchInput { longClick() }
+        textNode.performTextInputSelection(TextRange(2, 8))
+        textFieldValue.value = "Hello"
+
+        rule.waitForIdle()
+
+        val expected = TextRange(2, 5)
+        val actual = textNode.fetchSemanticsNode().config
+            .getOrNull(SemanticsProperties.TextSelectionRange)
+        assertThat(actual).isEqualTo(expected)
+    }
+
+    @Test
+    fun whenSelectedTextIsRemoved_addedLater_SelectionRemains() {
+        val textFieldValue = mutableStateOf("Hello")
+        rule.setContent {
+            BasicTextField(
+                value = textFieldValue.value,
+                onValueChange = {
+                    textFieldValue.value = it
+                },
+                modifier = Modifier.testTag(Tag).wrapContentSize()
+            )
+        }
+        val textNode = rule.onNodeWithTag(Tag)
+        textNode.performTouchInput { longClick() }
+        textNode.performTextInputSelection(TextRange(0, 4))
+        textFieldValue.value = ""
+        rule.waitForIdle()
+        textFieldValue.value = "Hello"
+
+        val expected = TextRange(0, 4)
+        val actual = textNode.fetchSemanticsNode().config
+            .getOrNull(SemanticsProperties.TextSelectionRange)
+        assertThat(actual).isEqualTo(expected)
+    }
+
+    @Test
+    fun whenSelectedTextIsRemovedByIME_SelectionDoesNotRevert() {
+        // hard to find a descriptive name. Take a look at
+        // `whenSelectedTextIsRemoved_addedLater_SelectionRemains` to understand this case better.
+
+        val textFieldValue = mutableStateOf("Hello")
+        rule.setContent {
+            BasicTextField(
+                value = textFieldValue.value,
+                onValueChange = {
+                    textFieldValue.value = it
+                },
+                modifier = Modifier.testTag(Tag).wrapContentSize()
+            )
+        }
+        val textNode = rule.onNodeWithTag(Tag)
+        textNode.performTouchInput { longClick() }
+        textNode.performTextInputSelection(TextRange(0, 4))
+        textNode.performKeyPress(backspaceKeyDown)
+        textNode.performKeyPress(backspaceKeyUp)
+
+        textFieldValue.value = "Hello"
+
+        rule.waitForIdle()
+
+        val expected = TextRange(0, 0)
+        val actual = textNode.fetchSemanticsNode().config
+            .getOrNull(SemanticsProperties.TextSelectionRange)
+        assertThat(actual).isEqualTo(expected)
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldSelectionTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldSelectionTest.kt
index 67472da..e30cb6b 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldSelectionTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldSelectionTest.kt
@@ -21,14 +21,25 @@
 import androidx.compose.foundation.text.selection.isSelectionHandle
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.assertCountEquals
 import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.click
 import androidx.compose.ui.test.isPopup
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.longClick
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.test.swipeRight
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.OffsetMapping
+import androidx.compose.ui.text.input.PasswordVisualTransformation
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.input.TransformedText
+import androidx.compose.ui.text.input.VisualTransformation
+import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
 
@@ -59,4 +70,144 @@
         rule.onNode(isSelectionHandle(Handle.SelectionStart)).assertIsDisplayed()
         rule.onNode(isSelectionHandle(Handle.SelectionEnd)).assertIsDisplayed()
     }
+
+    @Test
+    fun textField_showsSelectionHandles_whenVisualTransformationIsApplied() {
+        val testTag = "text field"
+        val textFieldValue = mutableStateOf(TextFieldValue("text text text"))
+        rule.setContent {
+            BasicTextField(
+                value = textFieldValue.value,
+                onValueChange = { textFieldValue.value = it },
+                visualTransformation = extraStarsVisualTransformation(),
+                modifier = Modifier.testTag(testTag)
+            )
+        }
+
+        // selection is not shown
+        rule.onAllNodes(isPopup()).assertCountEquals(0)
+
+        // make selection
+        rule.onNodeWithTag(testTag).performTouchInput { longClick() }
+        rule.waitForIdle()
+
+        rule.onNode(isSelectionHandle(Handle.SelectionStart)).assertIsDisplayed()
+        rule.onNode(isSelectionHandle(Handle.SelectionEnd)).assertIsDisplayed()
+    }
+
+    @Test
+    fun textField_showsCursorHandle() {
+        val testTag = "text field"
+        val textFieldValue = mutableStateOf("text text text")
+        rule.setContent {
+            BasicTextField(
+                value = textFieldValue.value,
+                onValueChange = { textFieldValue.value = it },
+                modifier = Modifier.testTag(testTag)
+            )
+        }
+
+        // selection is not shown
+        rule.onAllNodes(isPopup()).assertCountEquals(0)
+
+        // focus textfield, cursor should show
+        rule.onNodeWithTag(testTag).performTouchInput { click() }
+        rule.waitForIdle()
+
+        rule.onNode(isSelectionHandle(Handle.Cursor)).assertIsDisplayed()
+    }
+
+    @Test
+    fun textField_dragsCursorHandle() {
+        val testTag = "text field"
+        val textFieldValue =
+            mutableStateOf(TextFieldValue("text text text", TextRange(Int.MAX_VALUE)))
+        val cursorPositions = mutableListOf<Int>()
+        rule.setContent {
+            BasicTextField(
+                value = textFieldValue.value,
+                onValueChange = {
+                    textFieldValue.value = it
+                    if (it.selection.collapsed &&
+                        cursorPositions.lastOrNull() != it.selection.start
+                    ) {
+                        cursorPositions.add(it.selection.start)
+                    }
+                },
+                modifier = Modifier.testTag(testTag)
+            )
+        }
+
+        // selection is not shown
+        rule.onAllNodes(isPopup()).assertCountEquals(0)
+
+        var target = 0f
+        // focus textfield, cursor should show
+        rule.onNodeWithTag(testTag).performTouchInput {
+            click(Offset(0f, centerY))
+            target = right
+        }
+        rule.waitForIdle()
+
+        assertThat(textFieldValue.value.selection.start).isEqualTo(0)
+
+        rule.onNode(isSelectionHandle(Handle.Cursor)).performTouchInput {
+            swipeRight(startX = centerX, endX = centerX + target, durationMillis = 1000)
+        }
+
+        assertThat(cursorPositions).isEqualTo((0..14).toList())
+    }
+
+    @Test
+    fun textField_dragsCursorHandle_withVisualTransformation() {
+        val testTag = "text field"
+        val textFieldValue =
+            mutableStateOf(TextFieldValue("text text text", TextRange(Int.MAX_VALUE)))
+        val cursorPositions = mutableListOf<Int>()
+        rule.setContent {
+            BasicTextField(
+                value = textFieldValue.value,
+                onValueChange = {
+                    textFieldValue.value = it
+                    if (it.selection.collapsed &&
+                        cursorPositions.lastOrNull() != it.selection.start
+                    ) {
+                        cursorPositions.add(it.selection.start)
+                    }
+                },
+                visualTransformation = PasswordVisualTransformation(),
+                modifier = Modifier.testTag(testTag)
+            )
+        }
+
+        // selection is not shown
+        rule.onAllNodes(isPopup()).assertCountEquals(0)
+
+        var target = 0f
+        // focus textfield, cursor should show
+        rule.onNodeWithTag(testTag).performTouchInput {
+            click(Offset(0f, centerY))
+            target = right
+        }
+        rule.waitForIdle()
+
+        assertThat(textFieldValue.value.selection.start).isEqualTo(0)
+
+        rule.onNode(isSelectionHandle(Handle.Cursor)).performTouchInput {
+            swipeRight(startX = centerX, endX = centerX + target, durationMillis = 1000)
+        }
+
+        assertThat(cursorPositions).isEqualTo((0..14).toList())
+    }
+
+    private fun extraStarsVisualTransformation(): VisualTransformation {
+        return VisualTransformation {
+            TransformedText(
+                text = AnnotatedString(it.text.flatMap { listOf(it, '*') }.joinToString("")),
+                offsetMapping = object : OffsetMapping {
+                    override fun originalToTransformed(offset: Int) = offset * 2
+                    override fun transformedToOriginal(offset: Int) = offset / 2
+                })
+        }
+    }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
index 1a75b6c..1f0519e 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/Scrollable.kt
@@ -310,12 +310,18 @@
         else -> Offset(0f, this)
     }
 
+    fun Offset.singleAxisOffset(): Offset =
+        if (orientation == Horizontal) copy(y = 0f) else copy(x = 0f)
+
     fun Offset.toFloat(): Float =
         if (orientation == Horizontal) this.x else this.y
 
     fun Velocity.toFloat(): Float =
         if (orientation == Horizontal) this.x else this.y
 
+    fun Velocity.singleAxisVelocity(): Velocity =
+        if (orientation == Horizontal) copy(y = 0f) else copy(x = 0f)
+
     fun Velocity.update(newValue: Float): Velocity =
         if (orientation == Horizontal) copy(x = newValue) else copy(y = newValue)
 
@@ -328,12 +334,7 @@
         pointerPosition: Offset?,
         source: NestedScrollSource
     ): Offset {
-        val overscrollPreConsumed =
-            if (overscrollEffect != null && overscrollEffect.isEnabled) {
-                overscrollEffect.consumePreScroll(scrollDelta, pointerPosition, source)
-            } else {
-                Offset.Zero
-            }
+        val overscrollPreConsumed = overscrollPreConsumeDelta(scrollDelta, pointerPosition, source)
 
         val afterPreOverscroll = scrollDelta - overscrollPreConsumed
         val nestedScrollDispatcher = nestedScrollDispatcher.value
@@ -349,15 +350,43 @@
         val leftForParent = scrollAvailable - axisConsumed
         val parentConsumed = nestedScrollDispatcher
             .dispatchPostScroll(axisConsumed, leftForParent, source)
+
+        overscrollPostConsumeDelta(
+            scrollAvailable,
+            leftForParent - parentConsumed,
+            pointerPosition,
+            source
+        )
+        return leftForParent
+    }
+
+    fun overscrollPreConsumeDelta(
+        scrollDelta: Offset,
+        pointerPosition: Offset?,
+        source: NestedScrollSource
+    ): Offset {
+        return if (overscrollEffect != null && overscrollEffect.isEnabled) {
+            val overscrollAvailableDelta = scrollDelta.singleAxisOffset()
+            overscrollEffect.consumePreScroll(overscrollAvailableDelta, pointerPosition, source)
+        } else {
+            Offset.Zero
+        }
+    }
+
+    private fun overscrollPostConsumeDelta(
+        consumedByChain: Offset,
+        availableForOverscroll: Offset,
+        pointerPosition: Offset?,
+        source: NestedScrollSource
+    ) {
         if (overscrollEffect != null && overscrollEffect.isEnabled) {
             overscrollEffect.consumePostScroll(
-                scrollAvailable,
-                (leftForParent - parentConsumed),
+                consumedByChain.singleAxisOffset(),
+                availableForOverscroll.singleAxisOffset(),
                 pointerPosition,
                 source
             )
         }
-        return leftForParent
     }
 
     fun performRawScroll(scroll: Offset): Offset {
@@ -372,7 +401,9 @@
     suspend fun onDragStopped(initialVelocity: Velocity) {
         val preOverscrollConsumed =
             if (overscrollEffect != null && overscrollEffect.isEnabled) {
-                overscrollEffect.consumePreFling(initialVelocity)
+                val availableForOverscroll = initialVelocity.singleAxisVelocity()
+                val crossAxisRemainder = initialVelocity - availableForOverscroll
+                crossAxisRemainder + overscrollEffect.consumePreFling(availableForOverscroll)
             } else {
                 Velocity.Zero
             }
@@ -387,7 +418,7 @@
             )
         val totalLeft = velocityLeft - consumedPost
         if (overscrollEffect != null && overscrollEffect.isEnabled) {
-            overscrollEffect.consumePostFling(totalLeft)
+            overscrollEffect.consumePostFling(totalLeft.singleAxisVelocity())
         }
     }
 
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicText.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicText.kt
index abb13b2..a4fdebf 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicText.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicText.kt
@@ -85,10 +85,13 @@
 
     // NOTE(text-perf-review): potential bug. selectableId is regenerated here whenever text
     // changes, but it is only saved in the initial creation of TextState.
-    val selectableId =
+    val selectableId = if (selectionRegistrar == null) {
+        SelectionRegistrar.InvalidSelectableId
+    } else {
         rememberSaveable(text, selectionRegistrar, saver = selectionIdSaver(selectionRegistrar)) {
-            selectionRegistrar?.nextSelectableId() ?: SelectionRegistrar.InvalidSelectableId
+            selectionRegistrar.nextSelectableId()
         }
+    }
 
     val controller = remember {
         TextController(
@@ -184,10 +187,13 @@
 
     // NOTE(text-perf-review): potential bug. selectableId is regenerated here whenever text
     // changes, but it is only saved in the initial creation of TextState.
-    val selectableId =
+    val selectableId = if (selectionRegistrar == null) {
+        SelectionRegistrar.InvalidSelectableId
+    } else {
         rememberSaveable(text, selectionRegistrar, saver = selectionIdSaver(selectionRegistrar)) {
-            selectionRegistrar?.nextSelectableId() ?: SelectionRegistrar.InvalidSelectableId
+            selectionRegistrar.nextSelectableId()
         }
+    }
 
     val controller = remember {
         TextController(
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
index 9122b41..219470e 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
@@ -33,6 +33,7 @@
 import androidx.compose.foundation.text.selection.textFieldMagnifier
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.RecomposeScope
 import androidx.compose.runtime.currentRecomposeScope
 import androidx.compose.runtime.getValue
@@ -234,6 +235,7 @@
         )
     }
     state.update(
+        value.annotatedString,
         visualText,
         textStyle,
         softWrap,
@@ -653,7 +655,7 @@
 
 /**
  * Indicates which handle is being dragged when the user is dragging on a text field handle.
- * @see TextFieldState.draggingHandle
+ * @see TextFieldState.handleState
  */
 internal enum class Handle {
     Cursor,
@@ -705,7 +707,23 @@
      * position using the [TextFieldValue.selection] value which corresponds to the text directly,
      * and therefore does not require the translation.
      */
-    var layoutResult: TextLayoutResultProxy? by mutableStateOf(null)
+    private val layoutResultState: MutableState<TextLayoutResultProxy?> = mutableStateOf(null)
+    var layoutResult: TextLayoutResultProxy?
+        get() = layoutResultState.value
+        set(value) {
+            layoutResultState.value = value
+            isLayoutResultStale = false
+        }
+
+    /**
+     * [textDelegate] keeps a reference to the visually transformed text that is visible to the
+     * user. TextFieldState needs to have access to the underlying value that is not transformed
+     * while making comparisons that test whether the user input actually changed.
+     *
+     * This field contains the real value that is passed by the user before it was visually
+     * transformed.
+     */
+    var untransformedText: AnnotatedString? = null
 
     /**
      * The gesture detector state, to indicate whether current state is selection, cursor
@@ -749,6 +767,16 @@
      */
     var showCursorHandle by mutableStateOf(false)
 
+    /**
+     * TextFieldState holds both TextDelegate and layout result. However, these two values are not
+     * updated at the same time. TextDelegate is updated during composition according to new
+     * arguments while layoutResult is updated during layout phase. Therefore, [layoutResult] might
+     * not indicate the result of [textDelegate] at a given time during composition. This variable
+     * indicates whether layout result is lacking behind the latest TextDelegate.
+     */
+    var isLayoutResultStale: Boolean = true
+        private set
+
     private val keyboardActionRunner: KeyboardActionRunner = KeyboardActionRunner()
 
     /**
@@ -759,7 +787,7 @@
     private var onValueChangeOriginal: (TextFieldValue) -> Unit = {}
 
     val onValueChange: (TextFieldValue) -> Unit = {
-        if (it.text != textDelegate.text.text) {
+        if (it.text != untransformedText?.text) {
             // Text has been changed, enter the HandleState.None and hide the cursor handle.
             handleState = HandleState.None
         }
@@ -775,6 +803,7 @@
     val selectionPaint: Paint = Paint()
 
     fun update(
+        untransformedText: AnnotatedString,
         visualText: AnnotatedString,
         textStyle: TextStyle,
         softWrap: Boolean,
@@ -791,8 +820,9 @@
             this.keyboardActions = keyboardActions
             this.focusManager = focusManager
         }
+        this.untransformedText = untransformedText
 
-        textDelegate = updateTextDelegate(
+        val newTextDelegate = updateTextDelegate(
             current = textDelegate,
             text = visualText,
             style = textStyle,
@@ -801,6 +831,9 @@
             fontFamilyResolver = fontFamilyResolver,
             placeholders = emptyList(),
         )
+
+        if (textDelegate !== newTextDelegate) isLayoutResultStale = true
+        textDelegate = newTextDelegate
     }
 }
 
@@ -896,9 +929,11 @@
 
 @Composable
 private fun SelectionToolbarAndHandles(manager: TextFieldSelectionManager, show: Boolean) {
-    if (show) {
-        with(manager) {
-            state?.layoutResult?.value?.let {
+    with(manager) {
+        if (show) {
+            // Check whether text layout result became stale. A stale text layout might be
+            // completely unrelated to current TextFieldValue, causing offset errors.
+            state?.layoutResult?.value?.takeIf { !(state?.isLayoutResultStale ?: true) }?.let {
                 if (!value.selection.collapsed) {
                     val startOffset = offsetMapping.originalToTransformed(value.selection.start)
                     val endOffset = offsetMapping.originalToTransformed(value.selection.end)
@@ -931,8 +966,8 @@
                     }
                 }
             }
-        }
-    } else manager.hideSelectionToolbar()
+        } else hideSelectionToolbar()
+    }
 }
 
 @Composable
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionContainer.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionContainer.kt
index 6cfc11f..684df3b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionContainer.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/SelectionContainer.kt
@@ -34,7 +34,7 @@
 import androidx.compose.ui.util.fastForEach
 
 /**
- * Enables text selection for it's direct or indirection children.
+ * Enables text selection for it's direct or indirect children.
  *
  * @sample androidx.compose.foundation.samples.SelectionSample
  */
@@ -52,7 +52,7 @@
 }
 
 /**
- * Disables text selection for it's direct or indirection children. To use this, simply add this
+ * Disables text selection for it's direct or indirect children. To use this, simply add this
  * to wrap one or more text composables.
  *
  * @sample androidx.compose.foundation.samples.DisableSelectionSample
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
index 28808bb..1c7652b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
@@ -429,7 +429,9 @@
 
             state?.layoutResult?.value?.let { layoutResult ->
                 currentDragPosition = dragBeginPosition + dragTotalDistance
-                val offset = layoutResult.getOffsetForPosition(currentDragPosition!!)
+                val offset = offsetMapping.transformedToOriginal(
+                    layoutResult.getOffsetForPosition(currentDragPosition!!)
+                )
 
                 val newSelection = TextRange(offset, offset)
 
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
index 9fbceabd..f4926c9 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
@@ -36,6 +36,8 @@
 import androidx.compose.ui.text.input.OffsetMapping
 import androidx.compose.ui.text.input.PasswordVisualTransformation
 import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.input.TransformedText
+import androidx.compose.ui.text.input.VisualTransformation
 import androidx.compose.ui.text.style.ResolvedTextDirection
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.Constraints
@@ -315,6 +317,27 @@
     }
 
     @Test
+    fun TextFieldSelectionManager_cursorDragObserver_onDrag_withVisualTransformation() {
+        // there is a placeholder after every other char in the original value
+        val offsetMapping = object : OffsetMapping {
+            override fun originalToTransformed(offset: Int) = 2 * offset
+            override fun transformedToOriginal(offset: Int) = offset / 2
+        }
+        manager.value = TextFieldValue(text = "H*e*l*l*o* *W*o*r*l*d", selection = TextRange(0, 0))
+        manager.offsetMapping = offsetMapping
+        manager.visualTransformation = VisualTransformation { original ->
+            TransformedText(
+                AnnotatedString(original.indices.map { original[it] }.joinToString("*")),
+                offsetMapping
+            )
+        }
+
+        manager.cursorDragObserver().onDrag(dragDistance)
+
+        assertThat(value.selection).isEqualTo(TextRange(dragOffset / 2, dragOffset / 2))
+    }
+
+    @Test
     fun TextFieldSelectionManager_cursorDragObserver_onStop() {
         manager.handleDragObserver(false).onStart(Offset.Zero)
         manager.handleDragObserver(false).onDrag(Offset.Zero)
diff --git a/compose/material/material/lint-baseline.xml b/compose/material/material/lint-baseline.xml
deleted file mode 100644
index 6c2f717..0000000
--- a/compose/material/material/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 26 (current min is 21): `captureToImage`"
-        errorLine1="            .captureToImage()"
-        errorLine2="             ~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/material/BadgeTest.kt"/>
-    </issue>
-
-</issues>
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ScaffoldTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ScaffoldTest.kt
index 23b522c..a85fd4f 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ScaffoldTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ScaffoldTest.kt
@@ -17,6 +17,7 @@
 package androidx.compose.material
 
 import android.os.Build
+import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.PaddingValues
@@ -27,7 +28,9 @@
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Favorite
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.shadow
 import androidx.compose.ui.geometry.Offset
@@ -40,6 +43,7 @@
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.test.assertHeightIsEqualTo
+import androidx.compose.ui.test.assertIsDisplayed
 import androidx.compose.ui.test.assertWidthIsEqualTo
 import androidx.compose.ui.test.captureToImage
 import androidx.compose.ui.test.junit4.createComposeRule
@@ -418,6 +422,66 @@
     }
 
     @Test
+    fun scaffold_geometry_animated_fabSize() {
+        val fabTestTag = "FAB TAG"
+        lateinit var showFab: MutableState<Boolean>
+        var actualFabSize: IntSize = IntSize.Zero
+        var actualFabPlacement: FabPlacement? = null
+        rule.setContent {
+            showFab = remember { mutableStateOf(true) }
+            val animatedFab = @Composable {
+                AnimatedVisibility(visible = showFab.value) {
+                    FloatingActionButton(
+                        modifier = Modifier.onGloballyPositioned { positioned ->
+                            actualFabSize = positioned.size
+                        }.testTag(fabTestTag),
+                        onClick = {}
+                    ) {
+                        Icon(Icons.Filled.Favorite, null)
+                    }
+                }
+            }
+            Scaffold(
+                floatingActionButton = animatedFab,
+                floatingActionButtonPosition = FabPosition.End,
+                bottomBar = {
+                    actualFabPlacement = LocalFabPlacement.current
+                }
+            ) {
+                Text("body")
+            }
+        }
+
+        val fabNode = rule.onNodeWithTag(fabTestTag)
+
+        fabNode.assertIsDisplayed()
+
+        rule.runOnIdle {
+            assertThat(actualFabPlacement?.width).isEqualTo(actualFabSize.width)
+            assertThat(actualFabPlacement?.height).isEqualTo(actualFabSize.height)
+            actualFabSize = IntSize.Zero
+            actualFabPlacement = null
+            showFab.value = false
+        }
+
+        fabNode.assertDoesNotExist()
+
+        rule.runOnIdle {
+            assertThat(actualFabPlacement).isNull()
+            actualFabSize = IntSize.Zero
+            actualFabPlacement = null
+            showFab.value = true
+        }
+
+        fabNode.assertIsDisplayed()
+
+        rule.runOnIdle {
+            assertThat(actualFabPlacement?.width).isEqualTo(actualFabSize.width)
+            assertThat(actualFabPlacement?.height).isEqualTo(actualFabSize.height)
+        }
+    }
+
+    @Test
     fun scaffold_innerPadding_lambdaParam() {
         var bottomBarSize: IntSize = IntSize.Zero
         lateinit var innerPadding: PaddingValues
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
index 8912f1c..82bef6b 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
@@ -592,6 +592,34 @@
     }
 
     @Test
+    fun slider_setProgress_callsOnValueChangeFinished() {
+        val state = mutableStateOf(0f)
+        val callCount = mutableStateOf(0)
+
+        rule.setMaterialContent {
+            Slider(
+                modifier = Modifier.testTag(tag),
+                value = state.value,
+                onValueChangeFinished = {
+                    callCount.value += 1
+                },
+                onValueChange = { state.value = it }
+            )
+        }
+
+        rule.runOnIdle {
+            Truth.assertThat(callCount.value).isEqualTo(0)
+        }
+
+        rule.onNodeWithTag(tag)
+            .performSemanticsAction(SemanticsActions.SetProgress) { it(0.8f) }
+
+        rule.runOnIdle {
+            Truth.assertThat(callCount.value).isEqualTo(1)
+        }
+    }
+
+    @Test
     fun slider_interactionSource_resetWhenDisposed() {
         val interactionSource = MutableInteractionSource()
         var emitSlider by mutableStateOf(true)
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt
index d8cd090..c49d3c7 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt
@@ -254,30 +254,34 @@
             val snackbarHeight = snackbarPlaceables.fastMaxBy { it.height }?.height ?: 0
 
             val fabPlaceables =
-                subcompose(ScaffoldLayoutContent.Fab, fab).mapNotNull { measurable ->
-                    measurable.measure(looseConstraints).takeIf { it.height != 0 && it.width != 0 }
+                subcompose(ScaffoldLayoutContent.Fab, fab).fastMap { measurable ->
+                    measurable.measure(looseConstraints)
                 }
 
             val fabPlacement = if (fabPlaceables.isNotEmpty()) {
-                val fabWidth = fabPlaceables.fastMaxBy { it.width }!!.width
-                val fabHeight = fabPlaceables.fastMaxBy { it.height }!!.height
+                val fabWidth = fabPlaceables.fastMaxBy { it.width }?.width ?: 0
+                val fabHeight = fabPlaceables.fastMaxBy { it.height }?.height ?: 0
                 // FAB distance from the left of the layout, taking into account LTR / RTL
-                val fabLeftOffset = if (fabPosition == FabPosition.End) {
-                    if (layoutDirection == LayoutDirection.Ltr) {
-                        layoutWidth - FabSpacing.roundToPx() - fabWidth
+                if (fabWidth != 0 && fabHeight != 0) {
+                    val fabLeftOffset = if (fabPosition == FabPosition.End) {
+                        if (layoutDirection == LayoutDirection.Ltr) {
+                            layoutWidth - FabSpacing.roundToPx() - fabWidth
+                        } else {
+                            FabSpacing.roundToPx()
+                        }
                     } else {
-                        FabSpacing.roundToPx()
+                        (layoutWidth - fabWidth) / 2
                     }
-                } else {
-                    (layoutWidth - fabWidth) / 2
-                }
 
-                FabPlacement(
-                    isDocked = isFabDocked,
-                    left = fabLeftOffset,
-                    width = fabWidth,
-                    height = fabHeight
-                )
+                    FabPlacement(
+                        isDocked = isFabDocked,
+                        left = fabLeftOffset,
+                        width = fabWidth,
+                        height = fabHeight
+                    )
+                } else {
+                    null
+                }
             } else {
                 null
             }
@@ -334,10 +338,8 @@
                 it.place(0, layoutHeight - bottomBarHeight)
             }
             // Explicitly not using placeRelative here as `leftOffset` already accounts for RTL
-            fabPlacement?.let { placement ->
-                fabPlaceables.fastForEach {
-                    it.place(placement.left, layoutHeight - fabOffsetFromBottom!!)
-                }
+            fabPlaceables.fastForEach {
+                it.place(fabPlacement?.left ?: 0, layoutHeight - (fabOffsetFromBottom ?: 0))
             }
         }
     }
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
index 339aa65..580ab3a 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
@@ -163,7 +163,14 @@
         modifier
             .minimumTouchTargetSize()
             .requiredSizeIn(minWidth = ThumbRadius * 2, minHeight = ThumbRadius * 2)
-            .sliderSemantics(value, enabled, onValueChange, valueRange, steps)
+            .sliderSemantics(
+                value,
+                enabled,
+                onValueChange,
+                onValueChangeFinished,
+                valueRange,
+                steps
+            )
             .focusable(enabled, interactionSource)
     ) {
         val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
@@ -407,6 +414,7 @@
             coercedStart,
             enabled,
             { value -> onValueChangeState.value.invoke(value..coercedEnd) },
+            onValueChangeFinished,
             valueRange.start..coercedEnd,
             startSteps
         )
@@ -414,6 +422,7 @@
             coercedEnd,
             enabled,
             { value -> onValueChangeState.value.invoke(coercedStart..value) },
+            onValueChangeFinished,
             coercedStart..valueRange.endInclusive,
             endSteps
         )
@@ -842,6 +851,7 @@
     value: Float,
     enabled: Boolean,
     onValueChange: (Float) -> Unit,
+    onValueChangeFinished: (() -> Unit)? = null,
     valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
     steps: Int = 0
 ): Modifier {
@@ -874,6 +884,7 @@
                     false
                 } else {
                     onValueChange(resolvedValue)
+                    onValueChangeFinished?.invoke()
                     true
                 }
             }
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 2764de3..cf95a0f 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -85,6 +85,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation elevatedButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors filledTonalButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation filledTonalButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method public androidx.compose.foundation.layout.PaddingValues getButtonWithIconContentPadding();
     method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledTonalShape();
@@ -99,6 +100,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getTextShape();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors outlinedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors textButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    property public final androidx.compose.foundation.layout.PaddingValues ButtonWithIconContentPadding;
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
     property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape ElevatedShape;
     property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape FilledTonalShape;
@@ -343,6 +345,9 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled, boolean checked);
   }
 
+  public final class IncludeFontPaddingHelper_androidKt {
+  }
+
   @androidx.compose.runtime.Stable public interface ListItemColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> headlineColor(boolean enabled);
@@ -451,8 +456,6 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
   public final class ProgressIndicatorDefaults {
@@ -664,35 +667,6 @@
     method @androidx.compose.runtime.Composable public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
   }
 
-  @androidx.compose.runtime.Stable public interface TextFieldColors {
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean enabled);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> cursorColor(boolean isError);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> indicatorColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> labelColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> leadingIconColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> placeholderColor(boolean enabled);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> textColor(boolean enabled);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> trailingIconColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
-  }
-
-  @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
-    method public float getFocusedBorderThickness();
-    method public float getMinHeight();
-    method public float getMinWidth();
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
-    method public float getUnfocusedBorderThickness();
-    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
-    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
-    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape FilledShape;
-    property public final float FocusedBorderThickness;
-    property public final float MinHeight;
-    property public final float MinWidth;
-    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape OutlinedShape;
-    property public final float UnfocusedBorderThickness;
-    field public static final androidx.compose.material3.TextFieldDefaults INSTANCE;
-  }
-
   public final class TextFieldDefaultsKt {
   }
 
@@ -700,8 +674,6 @@
   }
 
   public final class TextFieldKt {
-    method @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
   public final class TextKt {
diff --git a/compose/material3/material3/api/public_plus_experimental_current.txt b/compose/material3/material3/api/public_plus_experimental_current.txt
index 44e6450..1d21786 100644
--- a/compose/material3/material3/api/public_plus_experimental_current.txt
+++ b/compose/material3/material3/api/public_plus_experimental_current.txt
@@ -100,6 +100,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation elevatedButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors filledTonalButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation filledTonalButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method public androidx.compose.foundation.layout.PaddingValues getButtonWithIconContentPadding();
     method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledTonalShape();
@@ -114,6 +115,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getTextShape();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors outlinedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors textButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    property public final androidx.compose.foundation.layout.PaddingValues ButtonWithIconContentPadding;
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
     property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape ElevatedShape;
     property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape FilledTonalShape;
@@ -484,6 +486,9 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled, boolean checked);
   }
 
+  public final class IncludeFontPaddingHelper_androidKt {
+  }
+
   @androidx.compose.material3.ExperimentalMaterial3Api public final class InputChipDefaults {
     method public float getAvatarSize();
     method public float getHeight();
@@ -628,8 +633,8 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
   public final class ProgressIndicatorDefaults {
@@ -879,7 +884,7 @@
     method @androidx.compose.runtime.Composable public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
   }
 
-  @androidx.compose.runtime.Stable public interface TextFieldColors {
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Stable public interface TextFieldColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> cursorColor(boolean isError);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> indicatorColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
@@ -890,7 +895,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> trailingIconColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
   }
 
-  @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
+  @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void BorderBox(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional androidx.compose.ui.graphics.Shape shape, optional float focusedBorderThickness, optional float unfocusedBorderThickness);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void OutlinedTextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function0<kotlin.Unit> border);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public void TextFieldDecorationBox(String value, kotlin.jvm.functions.Function0<kotlin.Unit> innerTextField, boolean enabled, boolean singleLine, androidx.compose.ui.text.input.VisualTransformation visualTransformation, androidx.compose.foundation.interaction.InteractionSource interactionSource, optional boolean isError, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.material3.TextFieldColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding);
@@ -901,9 +906,9 @@
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
     method public float getUnfocusedBorderThickness();
     method @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.ui.Modifier indicatorLine(androidx.compose.ui.Modifier, boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource, androidx.compose.material3.TextFieldColors colors, optional float focusedIndicatorLineThickness, optional float unfocusedIndicatorLineThickness);
-    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
     method @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.foundation.layout.PaddingValues outlinedTextFieldPadding(optional float start, optional float top, optional float end, optional float bottom);
-    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
     method @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.foundation.layout.PaddingValues textFieldWithLabelPadding(optional float start, optional float end, optional float top, optional float bottom);
     method @androidx.compose.material3.ExperimentalMaterial3Api public androidx.compose.foundation.layout.PaddingValues textFieldWithoutLabelPadding(optional float start, optional float top, optional float end, optional float bottom);
     property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape FilledShape;
@@ -922,8 +927,8 @@
   }
 
   public final class TextFieldKt {
-    method @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
   public final class TextKt {
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 2764de3..cf95a0f 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -85,6 +85,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation elevatedButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors filledTonalButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonElevation filledTonalButtonElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float disabledElevation);
+    method public androidx.compose.foundation.layout.PaddingValues getButtonWithIconContentPadding();
     method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getElevatedShape();
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledTonalShape();
@@ -99,6 +100,7 @@
     method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getTextShape();
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors outlinedButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.ButtonColors textButtonColors(optional long containerColor, optional long contentColor, optional long disabledContainerColor, optional long disabledContentColor);
+    property public final androidx.compose.foundation.layout.PaddingValues ButtonWithIconContentPadding;
     property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
     property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape ElevatedShape;
     property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape FilledTonalShape;
@@ -343,6 +345,9 @@
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled, boolean checked);
   }
 
+  public final class IncludeFontPaddingHelper_androidKt {
+  }
+
   @androidx.compose.runtime.Stable public interface ListItemColors {
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean enabled);
     method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> headlineColor(boolean enabled);
@@ -451,8 +456,6 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
   public final class ProgressIndicatorDefaults {
@@ -664,35 +667,6 @@
     method @androidx.compose.runtime.Composable public static void TabRow(int selectedTabIndex, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.material3.TabPosition>,kotlin.Unit> indicator, optional kotlin.jvm.functions.Function0<kotlin.Unit> divider, kotlin.jvm.functions.Function0<kotlin.Unit> tabs);
   }
 
-  @androidx.compose.runtime.Stable public interface TextFieldColors {
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean enabled);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> cursorColor(boolean isError);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> indicatorColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> labelColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> leadingIconColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> placeholderColor(boolean enabled);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> textColor(boolean enabled);
-    method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> trailingIconColor(boolean enabled, boolean isError, androidx.compose.foundation.interaction.InteractionSource interactionSource);
-  }
-
-  @androidx.compose.runtime.Immutable public final class TextFieldDefaults {
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getFilledShape();
-    method public float getFocusedBorderThickness();
-    method public float getMinHeight();
-    method public float getMinWidth();
-    method @androidx.compose.runtime.Composable public androidx.compose.ui.graphics.Shape getOutlinedShape();
-    method public float getUnfocusedBorderThickness();
-    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors outlinedTextFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional long focusedBorderColor, optional long unfocusedBorderColor, optional long disabledBorderColor, optional long errorBorderColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
-    method @androidx.compose.runtime.Composable public androidx.compose.material3.TextFieldColors textFieldColors(optional long textColor, optional long disabledTextColor, optional long containerColor, optional long cursorColor, optional long errorCursorColor, optional long focusedIndicatorColor, optional long unfocusedIndicatorColor, optional long disabledIndicatorColor, optional long errorIndicatorColor, optional long focusedLeadingIconColor, optional long unfocusedLeadingIconColor, optional long disabledLeadingIconColor, optional long errorLeadingIconColor, optional long focusedTrailingIconColor, optional long unfocusedTrailingIconColor, optional long disabledTrailingIconColor, optional long errorTrailingIconColor, optional long focusedLabelColor, optional long unfocusedLabelColor, optional long disabledLabelColor, optional long errorLabelColor, optional long placeholderColor, optional long disabledPlaceholderColor);
-    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape FilledShape;
-    property public final float FocusedBorderThickness;
-    property public final float MinHeight;
-    property public final float MinWidth;
-    property @androidx.compose.runtime.Composable public final androidx.compose.ui.graphics.Shape OutlinedShape;
-    property public final float UnfocusedBorderThickness;
-    field public static final androidx.compose.material3.TextFieldDefaults INSTANCE;
-  }
-
   public final class TextFieldDefaultsKt {
   }
 
@@ -700,8 +674,6 @@
   }
 
   public final class TextFieldKt {
-    method @androidx.compose.runtime.Composable public static void TextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
-    method @androidx.compose.runtime.Composable public static void TextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional boolean isError, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.TextFieldColors colors);
   }
 
   public final class TextKt {
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ButtonSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ButtonSamples.kt
index d9a844e..220c10f 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ButtonSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ButtonSamples.kt
@@ -65,7 +65,10 @@
 @Sampled
 @Composable
 fun ButtonWithIconSample() {
-    Button(onClick = { /* Do something! */ }) {
+    Button(
+        onClick = { /* Do something! */ },
+        contentPadding = ButtonDefaults.ButtonWithIconContentPadding
+    ) {
         Icon(
             Icons.Filled.Favorite,
             contentDescription = "Localized description",
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
index 78a0b68..34d1fe9 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/TextFieldSamples.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:OptIn(ExperimentalMaterial3Api::class)
+
 package androidx.compose.material3.samples
 
 import androidx.annotation.Sampled
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/NavigationBarTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/NavigationBarTest.kt
index 8f0d760..d708735 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/NavigationBarTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/NavigationBarTest.kt
@@ -215,20 +215,16 @@
         val itemBounds = rule.onNodeWithTag("item").getUnclippedBoundsInRoot()
         val iconBounds = rule.onNodeWithTag("icon", useUnmergedTree = true)
             .getUnclippedBoundsInRoot()
-        val textBounds = rule.onNodeWithText("ItemText").getUnclippedBoundsInRoot()
+        val textBounds = rule.onNodeWithText("ItemText", useUnmergedTree = true)
+            .getUnclippedBoundsInRoot()
 
-        // Distance from the bottom to the text baseline, and from the top of the icon to the
-        // top of the item
+        // Distance from the bottom of the item to the text bottom, and from the top of the icon to
+        // the top of the item
         val verticalPadding = NavigationBarItemVerticalPadding
 
-        // Relative position of the baseline to the top of text
-        val relativeTextBaseline = rule.onNodeWithText("ItemText").getLastBaselinePosition()
-        // Absolute y position of the text baseline
-        val absoluteTextBaseline = textBounds.top + relativeTextBaseline
-
         val itemBottom = itemBounds.height + itemBounds.top
-        // Text baseline should be `verticalPadding` from the bottom of the item
-        absoluteTextBaseline.assertIsEqualTo(itemBottom - verticalPadding)
+        // Text bottom should be `verticalPadding` from the bottom of the item
+        textBounds.bottom.assertIsEqualTo(itemBottom - verticalPadding)
 
         rule.onNodeWithTag("icon", useUnmergedTree = true)
             // The icon should be centered in the item
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt
index 08e2e1c..4b6409e 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldScreenshotTest.kt
@@ -53,6 +53,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
+@OptIn(ExperimentalMaterial3Api::class)
 @LargeTest
 @RunWith(AndroidJUnit4::class)
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
index 6ee82f7..f7edf54 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/OutlinedTextFieldTest.kt
@@ -92,6 +92,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
+@OptIn(ExperimentalMaterial3Api::class)
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 class OutlinedTextFieldTest {
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SliderTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SliderTest.kt
index 95ef9ed..93782c2 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SliderTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/SliderTest.kt
@@ -522,6 +522,34 @@
     }
 
     @Test
+    fun slider_setProgress_callsOnValueChangeFinished() {
+        val state = mutableStateOf(0f)
+        val callCount = mutableStateOf(0)
+
+        rule.setMaterialContent(lightColorScheme()) {
+            Slider(
+                modifier = Modifier.testTag(tag),
+                value = state.value,
+                onValueChangeFinished = {
+                    callCount.value += 1
+                },
+                onValueChange = { state.value = it }
+            )
+        }
+
+        rule.runOnIdle {
+            Truth.assertThat(callCount.value).isEqualTo(0)
+        }
+
+        rule.onNodeWithTag(tag)
+            .performSemanticsAction(SemanticsActions.SetProgress) { it(0.8f) }
+
+        rule.runOnIdle {
+            Truth.assertThat(callCount.value).isEqualTo(1)
+        }
+    }
+
+    @Test
     fun slider_interactionSource_resetWhenDisposed() {
         val interactionSource = MutableInteractionSource()
         var emitSlider by mutableStateOf(true)
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt
index ee57b40..997cb9d 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldScreenshotTest.kt
@@ -52,6 +52,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
+@OptIn(ExperimentalMaterial3Api::class)
 @LargeTest
 @RunWith(AndroidJUnit4::class)
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldTest.kt
index ac806d9..6da32cb 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextFieldTest.kt
@@ -111,6 +111,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
+@OptIn(ExperimentalMaterial3Api::class)
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 class TextFieldTest {
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextSelectionColorsScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextSelectionColorsScreenshotTest.kt
index 5a1a8d9..22fe7bf 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextSelectionColorsScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/TextSelectionColorsScreenshotTest.kt
@@ -217,6 +217,7 @@
 private fun FilledTextFieldTestContent(colorScheme: ColorScheme) {
     MaterialTheme(colorScheme) {
         Surface(Modifier.testTag(Tag)) {
+            @OptIn(ExperimentalMaterial3Api::class)
             TextField(
                 value = TextFieldText,
                 onValueChange = {},
@@ -230,6 +231,7 @@
 private fun OutlinedTextFieldTestContent(colorScheme: ColorScheme) {
     MaterialTheme(colorScheme) {
         Surface(Modifier.testTag(Tag)) {
+            @OptIn(ExperimentalMaterial3Api::class)
             OutlinedTextField(
                 value = TextFieldText,
                 onValueChange = {},
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.android.kt
new file mode 100644
index 0000000..d29b497
--- /dev/null
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.android.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.PlatformTextStyle
+import androidx.compose.ui.text.TextStyle
+
+// TODO(b/237588251) remove this once the default includeFontPadding is false
+@OptIn(ExperimentalTextApi::class)
+@Suppress("DEPRECATION")
+internal actual fun copyAndSetFontPadding(
+    style: TextStyle,
+    includeFontPadding: Boolean
+): TextStyle =
+    style.copy(platformStyle = PlatformTextStyle(includeFontPadding = includeFontPadding))
\ No newline at end of file
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt
index 3696f19..a19294f 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Badge.kt
@@ -169,8 +169,10 @@
             CompositionLocalProvider(
                 LocalContentColor provides contentColor
             ) {
-                val style =
-                    MaterialTheme.typography.fromToken(BadgeTokens.LargeLabelTextFont)
+                val style = copyAndSetFontPadding(
+                    style = MaterialTheme.typography.fromToken(BadgeTokens.LargeLabelTextFont),
+                    includeFontPadding = false
+                )
                 ProvideTextStyle(
                     value = style,
                     content = { content() }
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt
index 6c39046..a0b2199 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Button.kt
@@ -460,6 +460,7 @@
      * [OutlinedButton] buttons.
      *
      * - See [TextButtonContentPadding] for content padding used by [TextButton].
+     * - See [ButtonWithIconContentPadding] for content padding used by [Button] that contains [Icon].
      */
     // TODO(b/201343537): Use tokens.
     val ContentPadding =
@@ -470,6 +471,17 @@
             bottom = ButtonVerticalPadding
         )
 
+    private val ButtonWithIconHorizontalStartPadding = 16.dp
+
+    /** The default content padding used by [Button] that contains an [Icon]. */
+    val ButtonWithIconContentPadding =
+        PaddingValues(
+            start = ButtonWithIconHorizontalStartPadding,
+            top = ButtonVerticalPadding,
+            end = ButtonHorizontalPadding,
+            bottom = ButtonVerticalPadding
+        )
+
     // TODO(b/201344013): Make sure these values stay up to date until replaced with tokens.
     private val TextButtonHorizontalPadding = 12.dp
 
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.kt
new file mode 100644
index 0000000..e6ace4e
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/IncludeFontPaddingHelper.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.ui.text.TextStyle
+
+// TODO(b/237588251) remove this once the default includeFontPadding is false
+internal expect fun copyAndSetFontPadding(style: TextStyle, includeFontPadding: Boolean): TextStyle
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationBar.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationBar.kt
index c468caa..42541a1 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationBar.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationBar.kt
@@ -48,7 +48,6 @@
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.layout.LastBaseline
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.layout.MeasureResult
 import androidx.compose.ui.layout.MeasureScope
@@ -503,9 +502,8 @@
 ): MeasureResult {
     val height = constraints.maxHeight
 
-    val baseline = labelPlaceable[LastBaseline]
     // Label should be `ItemVerticalPadding` from the bottom
-    val labelY = height - baseline - NavigationBarItemVerticalPadding.roundToPx()
+    val labelY = height - labelPlaceable.height - NavigationBarItemVerticalPadding.roundToPx()
 
     // Icon (when selected) should be `ItemVerticalPadding` from the top
     val selectedIconY = NavigationBarItemVerticalPadding.roundToPx()
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
index bbdde55..68fdeca 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/OutlinedTextField.kt
@@ -125,6 +125,7 @@
  * @param colors [TextFieldColors] that will be used to resolve the colors used for this text field
  * in different states. See [TextFieldDefaults.outlinedTextFieldColors].
  */
+@ExperimentalMaterial3Api
 @Composable
 fun OutlinedTextField(
     value: String,
@@ -267,6 +268,7 @@
  * @param colors [TextFieldColors] that will be used to resolve the colors used for this text field
  * in different states. See [TextFieldDefaults.outlinedTextFieldColors].
  */
+@ExperimentalMaterial3Api
 @Composable
 fun OutlinedTextField(
     value: TextFieldValue,
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt
index de0d27c..dd9b2d9 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt
@@ -173,7 +173,14 @@
                 minWidth = SliderTokens.HandleWidth,
                 minHeight = SliderTokens.HandleHeight
             )
-            .sliderSemantics(value, enabled, onValueChange, valueRange, steps)
+            .sliderSemantics(
+                value,
+                enabled,
+                onValueChange,
+                onValueChangeFinished,
+                valueRange,
+                steps
+            )
             .focusable(enabled, interactionSource)
     ) {
         val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
@@ -378,6 +385,7 @@
             coercedStart,
             enabled,
             { value -> onValueChangeState.value.invoke(value..coercedEnd) },
+            onValueChangeFinished,
             valueRange.start..coercedEnd,
             startSteps
         )
@@ -385,6 +393,7 @@
             coercedEnd,
             enabled,
             { value -> onValueChangeState.value.invoke(coercedStart..value) },
+            onValueChangeFinished,
             coercedStart..valueRange.endInclusive,
             endSteps
         )
@@ -600,7 +609,7 @@
         val trackStrokeWidth: Float
         val widthDp: Dp
         with(LocalDensity.current) {
-            trackStrokeWidth = SliderTokens.ActiveTrackHeight.toPx()
+            trackStrokeWidth = TrackHeight.toPx()
             widthDp = width.toDp()
         }
 
@@ -680,8 +689,11 @@
     thumbWidth: Dp,
     trackStrokeWidth: Float
 ) {
-    val thumbRadiusPx = with(LocalDensity.current) {
-        thumbWidth.toPx() / 2
+    val thumbRadiusPx: Float
+    val tickSize: Float
+    with(LocalDensity.current) {
+        thumbRadiusPx = thumbWidth.toPx() / 2
+        tickSize = TickSize.toPx()
     }
     val inactiveTrackColor = colors.trackColor(enabled, active = false)
     val activeTrackColor = colors.trackColor(enabled, active = true)
@@ -725,7 +737,7 @@
                     },
                     PointMode.Points,
                     (if (outsideFraction) inactiveTickColor else activeTickColor).value,
-                    trackStrokeWidth,
+                    tickSize,
                     StrokeCap.Round
                 )
             }
@@ -778,6 +790,7 @@
     value: Float,
     enabled: Boolean,
     onValueChange: (Float) -> Unit,
+    onValueChangeFinished: (() -> Unit)? = null,
     valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
     steps: Int = 0
 ): Modifier {
@@ -812,6 +825,7 @@
                     false
                 } else {
                     onValueChange(resolvedValue)
+                    onValueChangeFinished?.invoke()
                     true
                 }
             }
@@ -1079,9 +1093,10 @@
 private val ThumbSize = DpSize(ThumbWidth, ThumbHeight)
 private val ThumbDefaultElevation = 1.dp
 private val ThumbPressedElevation = 6.dp
+private val TickSize = SliderTokens.TickMarksContainerSize
 
 // Internal to be referred to in tests
-internal val TrackHeight = 4.dp
+internal val TrackHeight = SliderTokens.InactiveTrackHeight
 private val SliderHeight = 48.dp
 private val SliderMinWidth = 144.dp // TODO: clarify min width
 private val DefaultSliderConstraints =
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
index 6fa1036c..f92aec7 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextField.kt
@@ -151,6 +151,7 @@
  * @param colors [TextFieldColors] that will be used to resolve the colors used for this text field
  * in different states. See [TextFieldDefaults.textFieldColors].
  */
+@ExperimentalMaterial3Api
 @Composable
 fun TextField(
     value: String,
@@ -283,6 +284,7 @@
  * @param colors [TextFieldColors] that will be used to resolve the colors used for this text field
  * in different states. See [TextFieldDefaults.textFieldColors].
  */
+@ExperimentalMaterial3Api
 @Composable
 fun TextField(
     value: TextFieldValue,
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
index 5d66ca1..3d65897 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TextFieldDefaults.kt
@@ -56,6 +56,7 @@
  * See [TextFieldDefaults.outlinedTextFieldColors] for the default colors used in
  * [OutlinedTextField].
  */
+@ExperimentalMaterial3Api
 @Stable
 interface TextFieldColors {
     /**
@@ -154,6 +155,7 @@
 /**
  * Contains the default values used by [TextField] and [OutlinedTextField].
  */
+@ExperimentalMaterial3Api
 @Immutable
 object TextFieldDefaults {
     /** Default shape for an outlined text field. */
@@ -337,6 +339,7 @@
      * @param placeholderColor the placeholder color for this text field
      * @param disabledPlaceholderColor the placeholder color for this text field when disabled
      */
+    @ExperimentalMaterial3Api
     @Composable
     fun textFieldColors(
         textColor: Color = FilledTextFieldTokens.InputColor.toColor(),
@@ -424,6 +427,7 @@
      * @param placeholderColor the placeholder color for this text field
      * @param disabledPlaceholderColor the placeholder color for this text field when disabled
      */
+    @ExperimentalMaterial3Api
     @Composable
     fun outlinedTextFieldColors(
         textColor: Color = OutlinedTextFieldTokens.InputColor.toColor(),
@@ -670,6 +674,7 @@
     }
 }
 
+@OptIn(ExperimentalMaterial3Api::class)
 @Immutable
 private class DefaultTextFieldColors(
     private val textColor: Color,
@@ -852,6 +857,7 @@
     }
 }
 
+@OptIn(ExperimentalMaterial3Api::class)
 @Composable
 private fun animateBorderStrokeAsState(
     enabled: Boolean,
diff --git a/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material/IncludeFontPaddingHelper.desktop.kt b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material/IncludeFontPaddingHelper.desktop.kt
new file mode 100644
index 0000000..31ecb1e
--- /dev/null
+++ b/compose/material3/material3/src/desktopMain/kotlin/androidx/compose/material/IncludeFontPaddingHelper.desktop.kt
@@ -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.
+ */
+
+package androidx.compose.material3
+
+import androidx.compose.ui.text.TextStyle
+
+// TODO(b/237588251) remove this once the default includeFontPadding is false
+/* NOOP includeFontPadding doesn't exist on desktop */
+internal actual fun copyAndSetFontPadding(
+    style: TextStyle,
+    includeFontPadding: Boolean
+): TextStyle = style
\ No newline at end of file
diff --git a/compose/runtime/runtime-tracing/api/current.txt b/compose/runtime/runtime-tracing/api/current.txt
new file mode 100644
index 0000000..716d534
--- /dev/null
+++ b/compose/runtime/runtime-tracing/api/current.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.compose.runtime.tracing {
+
+  public final class TracingInitializer implements androidx.startup.Initializer<kotlin.Unit> {
+    ctor public TracingInitializer();
+    method public void create(android.content.Context context);
+    method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>> dependencies();
+  }
+
+}
+
diff --git a/compose/runtime/runtime-tracing/api/public_plus_experimental_current.txt b/compose/runtime/runtime-tracing/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..716d534
--- /dev/null
+++ b/compose/runtime/runtime-tracing/api/public_plus_experimental_current.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.compose.runtime.tracing {
+
+  public final class TracingInitializer implements androidx.startup.Initializer<kotlin.Unit> {
+    ctor public TracingInitializer();
+    method public void create(android.content.Context context);
+    method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>> dependencies();
+  }
+
+}
+
diff --git a/development/gradleRemoteCache/data/.empty b/compose/runtime/runtime-tracing/api/res-current.txt
similarity index 100%
rename from development/gradleRemoteCache/data/.empty
rename to compose/runtime/runtime-tracing/api/res-current.txt
diff --git a/compose/runtime/runtime-tracing/api/restricted_current.txt b/compose/runtime/runtime-tracing/api/restricted_current.txt
new file mode 100644
index 0000000..716d534
--- /dev/null
+++ b/compose/runtime/runtime-tracing/api/restricted_current.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.compose.runtime.tracing {
+
+  public final class TracingInitializer implements androidx.startup.Initializer<kotlin.Unit> {
+    ctor public TracingInitializer();
+    method public void create(android.content.Context context);
+    method public java.util.List<java.lang.Class<? extends androidx.startup.Initializer<?>>> dependencies();
+  }
+
+}
+
diff --git a/compose/runtime/runtime-tracing/build.gradle b/compose/runtime/runtime-tracing/build.gradle
index 5211b24..c12bfd6 100644
--- a/compose/runtime/runtime-tracing/build.gradle
+++ b/compose/runtime/runtime-tracing/build.gradle
@@ -28,6 +28,7 @@
     defaultConfig {
         minSdkVersion 21
     }
+    namespace "androidx.compose.runtime.tracing"
 }
 
 dependencies {
@@ -49,12 +50,11 @@
 
 androidx {
     name = "Compose Runtime: Tracing"
-    runApiTasks= new RunApiTasks.No("The API is still evolving") // TODO(b/231444429)
     publish = Publish.SNAPSHOT_AND_RELEASE
     mavenVersion = LibraryVersions.COMPOSE_RUNTIME_TRACING
     mavenGroup = LibraryGroups.COMPOSE_RUNTIME
     inceptionYear = "2022"
-    description = "Allows for additional tracing in a Compose app (e.g. tracing of Composables taking part in a Recomposition"
+    description = "Additional tracing in Compose"
 }
 
 tasks.withType(KotlinCompile).configureEach {
diff --git a/compose/runtime/runtime-tracing/src/androidTest/AndroidManifest.xml b/compose/runtime/runtime-tracing/src/androidTest/AndroidManifest.xml
deleted file mode 100644
index 0b0410b..0000000
--- a/compose/runtime/runtime-tracing/src/androidTest/AndroidManifest.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<!--
-  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.
-  -->
-
-<!--
-  ~ 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.
-  -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.compose.runtime.tracing.test">
-
-</manifest>
diff --git a/compose/runtime/runtime-tracing/src/main/AndroidManifest.xml b/compose/runtime/runtime-tracing/src/main/AndroidManifest.xml
index b3f90e5..280bb2f 100644
--- a/compose/runtime/runtime-tracing/src/main/AndroidManifest.xml
+++ b/compose/runtime/runtime-tracing/src/main/AndroidManifest.xml
@@ -31,8 +31,7 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    package="androidx.compose.runtime.tracing">
+    xmlns:tools="http://schemas.android.com/tools">
 
     <application>
         <provider
diff --git a/compose/runtime/runtime/lint-baseline.xml b/compose/runtime/runtime/lint-baseline.xml
deleted file mode 100644
index 190f160..0000000
--- a/compose/runtime/runtime/lint-baseline.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha01" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha01)" variant="all" version="7.4.0-alpha01">
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline infix fun Int.ror(other: Int) = this.rotateRight(other)"
-        errorLine2="                              ~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/runtime/BitwiseOperators.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline infix fun Int.rol(other: Int) = this.rotateLeft(other)"
-        errorLine2="                              ~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/runtime/BitwiseOperators.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T> List&lt;T>.fastForEach(action: (T) -> Unit) {"
-        errorLine2="                                ~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T> List&lt;T>.fastForEachIndexed(action: (Int, T) -> Unit) {"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, R> List&lt;T>.fastMap(transform: (T) -> R): List&lt;R> {"
-        errorLine2="                                   ~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T> List&lt;T>.fastAny(predicate: (T) -> Boolean): Boolean {"
-        errorLine2="                                ~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T> List&lt;T>.fastAll(predicate: (T) -> Boolean): Boolean {"
-        errorLine2="                                ~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, K> List&lt;T>.fastGroupBy("
-        errorLine2="                                   ~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, R> List&lt;T>.fastMapNotNull(transform: (T) -> R?): List&lt;R> {"
-        errorLine2="                                   ~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T> List&lt;T>.fastFilterIndexed(predicate: (index: Int, T) -> Boolean): List&lt;T> {"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="        inline fun &lt;T> withoutReadObservation(block: @DisallowComposableCalls () -> T): T {"
-        errorLine2="                       ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt"/>
-    </issue>
-
-</issues>
diff --git a/compose/test-utils/src/commonMain/kotlin/androidx/compose/testutils/ComposeTestCase.kt b/compose/test-utils/src/commonMain/kotlin/androidx/compose/testutils/ComposeTestCase.kt
index 28460d1..5d5e032 100644
--- a/compose/test-utils/src/commonMain/kotlin/androidx/compose/testutils/ComposeTestCase.kt
+++ b/compose/test-utils/src/commonMain/kotlin/androidx/compose/testutils/ComposeTestCase.kt
@@ -17,6 +17,7 @@
 package androidx.compose.testutils
 
 import androidx.compose.runtime.Composable
+import androidx.compose.ui.UiComposable
 
 /**
  * To be implemented to provide a test case that is then executed by [ComposeTestRule] or can be
@@ -72,6 +73,7 @@
      * The lifecycle rules for this method are same as for [Content]
      */
     @Composable
+    @UiComposable
     open fun ContentWrappers(content: @Composable () -> Unit) {
         content()
     }
diff --git a/compose/ui/ui-test/api/public_plus_experimental_current.txt b/compose/ui/ui-test/api/public_plus_experimental_current.txt
index 6f8155d..23641cd 100644
--- a/compose/ui/ui-test/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-test/api/public_plus_experimental_current.txt
@@ -266,15 +266,11 @@
     method @androidx.compose.ui.test.ExperimentalTestApi public static boolean isFnDown(androidx.compose.ui.test.KeyInjectionScope);
     method @androidx.compose.ui.test.ExperimentalTestApi public static boolean isMetaDown(androidx.compose.ui.test.KeyInjectionScope);
     method @androidx.compose.ui.test.ExperimentalTestApi public static boolean isShiftDown(androidx.compose.ui.test.KeyInjectionScope);
-    method @androidx.compose.ui.test.ExperimentalTestApi public static void keysDown(androidx.compose.ui.test.KeyInjectionScope, java.util.List<androidx.compose.ui.input.key.Key> keys, optional long pauseDurationMillis);
-    method @androidx.compose.ui.test.ExperimentalTestApi public static void keysUp(androidx.compose.ui.test.KeyInjectionScope, java.util.List<androidx.compose.ui.input.key.Key> keys, optional long pauseDurationMillis);
     method @androidx.compose.ui.test.ExperimentalTestApi public static void pressKey(androidx.compose.ui.test.KeyInjectionScope, long key, optional long pressDurationMillis);
-    method @androidx.compose.ui.test.ExperimentalTestApi public static void pressKey(androidx.compose.ui.test.KeyInjectionScope, long key, int times, optional long pressDurationMillis, optional long pauseDurationMillis);
-    method @androidx.compose.ui.test.ExperimentalTestApi public static void pressKeys(androidx.compose.ui.test.KeyInjectionScope, java.util.List<androidx.compose.ui.input.key.Key> keys, optional long pressDurationMillis, optional long pauseDurationMillis);
-    method @androidx.compose.ui.test.ExperimentalTestApi public static void withKeyDown(androidx.compose.ui.test.KeyInjectionScope, long key, optional long pauseDurationMillis, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.KeyInjectionScope,kotlin.Unit> block);
-    method @androidx.compose.ui.test.ExperimentalTestApi public static void withKeyToggled(androidx.compose.ui.test.KeyInjectionScope, long key, optional long pauseDurationMillis, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.KeyInjectionScope,kotlin.Unit> block);
-    method @androidx.compose.ui.test.ExperimentalTestApi public static void withKeysDown(androidx.compose.ui.test.KeyInjectionScope, java.util.List<androidx.compose.ui.input.key.Key> keys, optional long pauseDurationMillis, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.KeyInjectionScope,kotlin.Unit> block);
-    method @androidx.compose.ui.test.ExperimentalTestApi public static void withKeysToggled(androidx.compose.ui.test.KeyInjectionScope, java.util.List<androidx.compose.ui.input.key.Key> keys, optional long pauseDurationMillis, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.KeyInjectionScope,kotlin.Unit> block);
+    method @androidx.compose.ui.test.ExperimentalTestApi public static void withKeyDown(androidx.compose.ui.test.KeyInjectionScope, long key, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.KeyInjectionScope,kotlin.Unit> block);
+    method @androidx.compose.ui.test.ExperimentalTestApi public static void withKeyToggled(androidx.compose.ui.test.KeyInjectionScope, long key, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.KeyInjectionScope,kotlin.Unit> block);
+    method @androidx.compose.ui.test.ExperimentalTestApi public static void withKeysDown(androidx.compose.ui.test.KeyInjectionScope, java.util.List<androidx.compose.ui.input.key.Key> keys, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.KeyInjectionScope,kotlin.Unit> block);
+    method @androidx.compose.ui.test.ExperimentalTestApi public static void withKeysToggled(androidx.compose.ui.test.KeyInjectionScope, java.util.List<androidx.compose.ui.input.key.Key> keys, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.KeyInjectionScope,kotlin.Unit> block);
   }
 
   public final class KeyInputHelpersKt {
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyDownTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyDownTest.kt
index b8bf432..6d6d75a 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyDownTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyDownTest.kt
@@ -24,7 +24,6 @@
 import androidx.compose.ui.test.injectionscope.key.Common.assertTyped
 import androidx.compose.ui.test.injectionscope.key.Common.performKeyInput
 import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.keysDown
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performClick
 import androidx.compose.ui.test.util.TestTextField
@@ -108,22 +107,4 @@
         }
         rule.assertTyped(":")
     }
-
-    @Test
-    fun downedKeys_areDown() {
-        rule.performKeyInput {
-            keysDown(listOf(Key.A, Key.Enter))
-            assertTrue(isKeyDown(Key.A))
-            assertTrue(isKeyDown(Key.Enter))
-        }
-    }
-
-    @Test
-    fun duplicates_inKeysDown_throwIllegalStateException() {
-        expectError<IllegalArgumentException>(
-            expectedMessage = "List of keys must not contain any duplicates."
-        ) {
-            rule.performKeyInput { keysDown(listOf(Key.A, Key.A)) }
-        }
-    }
 }
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyPressTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyPressTest.kt
index f4bd25d..913e47d 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyPressTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyPressTest.kt
@@ -18,7 +18,6 @@
 
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.input.key.Key
-import androidx.compose.ui.input.key.nativeKeyCode
 import androidx.compose.ui.test.ExperimentalTestApi
 import androidx.compose.ui.test.KeyInjectionScope
 import androidx.compose.ui.test.injectionscope.key.Common.assertTyped
@@ -27,7 +26,6 @@
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performClick
 import androidx.compose.ui.test.pressKey
-import androidx.compose.ui.test.pressKeys
 import androidx.compose.ui.test.util.TestTextField
 import androidx.compose.ui.test.util.TestTextField.Tag
 import androidx.test.filters.FlakyTest
@@ -37,7 +35,7 @@
 import org.junit.Test
 
 /**
- * Tests if [KeyInjectionScope.pressKey] and [KeyInjectionScope.pressKeys] work.
+ * Tests if [KeyInjectionScope.pressKey] works.
  */
 @LargeTest
 @OptIn(ExperimentalComposeUiApi::class, ExperimentalTestApi::class)
@@ -72,14 +70,7 @@
         rule.assertTyped("abb")
     }
 
-    @Test
-    fun typeAlphabet_withPressKeys() {
-        rule.performKeyInput {
-            pressKeys((Key.A.nativeKeyCode..Key.Z.nativeKeyCode).map { Key(it) }.toList())
-        }
-        rule.assertTyped(('a'..'z').joinToString(separator = ""))
-    }
-
+    @FlakyTest(bugId = 236864049)
     @Test
     fun pressingNumberKeys_typesNumberChars() {
         rule.performKeyInput { pressKey(Key.One) }
@@ -87,15 +78,6 @@
         rule.assertTyped("12")
     }
 
-    @FlakyTest(bugId = 236950171)
-    @Test
-    fun pressKeyMultipleTimes_pressesKey_correctNumberOfTimes() {
-        rule.performKeyInput {
-            pressKey(Key.A, 10)
-        }
-        rule.assertTyped((1..10).joinToString(separator = "") { "a" })
-    }
-
     @Test
     fun pressingBackspace_deletesLastCharacter() {
         rule.performKeyInput {
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyUpTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyUpTest.kt
index 25d6c3dc..4ded126 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyUpTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/KeyUpTest.kt
@@ -24,7 +24,6 @@
 import androidx.compose.ui.test.injectionscope.key.Common.assertTyped
 import androidx.compose.ui.test.injectionscope.key.Common.performKeyInput
 import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.keysUp
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performClick
 import androidx.compose.ui.test.util.TestTextField
@@ -91,27 +90,4 @@
         }
         rule.assertTyped("a")
     }
-
-    @Test
-    fun keysAreUp_after_keysUp() {
-        rule.performKeyInput {
-            keyDown(Key.A)
-            keyDown(Key.Enter)
-        }
-        rule.performKeyInput {
-            keysUp(listOf(Key.A, Key.Enter))
-            assertFalse(isKeyDown(Key.A))
-            assertFalse(isKeyDown(Key.Enter))
-        }
-    }
-
-    @Test
-    fun duplicates_inKeysDown_throwIllegalStateException() {
-        rule.performKeyInput { keyDown(Key.A) }
-        expectError<IllegalArgumentException>(
-            expectedMessage = "List of keys must not contain any duplicates."
-        ) {
-            rule.performKeyInput { keysUp(listOf(Key.A, Key.A)) }
-        }
-    }
 }
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/LockKeysTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/LockKeysTest.kt
index 659bc55..5cad927 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/LockKeysTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/LockKeysTest.kt
@@ -26,7 +26,6 @@
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performClick
 import androidx.compose.ui.test.pressKey
-import androidx.compose.ui.test.pressKeys
 import androidx.compose.ui.test.util.TestTextField
 import androidx.compose.ui.test.util.TestTextField.Tag
 import androidx.compose.ui.test.withKeyToggled
@@ -91,7 +90,10 @@
     fun lettersTyped_withCapsLockOn_areUppercase() {
         rule.performKeyInput {
             pressKey(Key.A)
-            withKeyToggled(Key.CapsLock) { pressKeys(listOf(Key.A, Key.B)) }
+            withKeyToggled(Key.CapsLock) {
+                pressKey(Key.A)
+                pressKey(Key.B)
+            }
             pressKey(Key.B)
         }
 
@@ -102,10 +104,14 @@
     fun withKeyToggled_turnsCapsLockOff_ifCapsLockAlreadyOn() {
         rule.performKeyInput {
             pressKey(Key.CapsLock)
-            pressKeys(listOf(Key.A, Key.B))
-            withKeyToggled(Key.CapsLock) { pressKeys(listOf(Key.A, Key.B)) }
-            pressKeys(listOf(Key.A, Key.B))
-        }
+            pressKey(Key.A)
+            pressKey(Key.B)
+            withKeyToggled(Key.CapsLock) {
+                pressKey(Key.A)
+                pressKey(Key.B)
+            }
+            pressKey(Key.A)
+            pressKey(Key.B) }
 
         rule.assertTyped("ABabAB")
     }
@@ -114,7 +120,10 @@
     fun numPadKeysPressed_withNumLockToggled_areNumbers() {
         rule.performKeyInput {
             pressKey(Key.NumPad0)
-            withKeyToggled(Key.NumLock) { pressKeys(listOf(Key.NumPad1, Key.NumPad0)) }
+            withKeyToggled(Key.NumLock) {
+                pressKey(Key.NumPad1)
+                pressKey(Key.NumPad0)
+            }
             pressKey(Key.NumPad1)
         }
 
@@ -125,8 +134,11 @@
     fun withKeyToggled_turnsNumLockOff_ifNumLockAlreadyOn() {
         rule.performKeyInput {
             pressKey(Key.NumLock)
-            pressKeys(listOf(Key.NumPad0, Key.NumPad1))
-            withKeyToggled(Key.NumLock) { pressKey(Key.NumPad0) }
+            pressKey(Key.NumPad0)
+            pressKey(Key.NumPad1)
+            withKeyToggled(Key.NumLock) {
+                pressKey(Key.NumPad0)
+            }
         }
 
         rule.assertTyped("01")
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/MetaKeysTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/MetaKeysTest.kt
index 729ea87..ccdf060 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/MetaKeysTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/injectionscope/key/MetaKeysTest.kt
@@ -32,7 +32,6 @@
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performClick
 import androidx.compose.ui.test.pressKey
-import androidx.compose.ui.test.pressKeys
 import androidx.compose.ui.test.util.TestTextField
 import androidx.compose.ui.test.util.TestTextField.Tag
 import androidx.compose.ui.test.withKeyDown
@@ -114,7 +113,10 @@
     fun lettersTyped_withShiftDown_areUppercase() {
         rule.performKeyInput {
             pressKey(Key.A)
-            withKeyDown(Key.ShiftLeft) { pressKeys(listOf(Key.A, Key.B)) }
+            withKeyDown(Key.ShiftLeft) {
+                pressKey(Key.A)
+                pressKey(Key.B)
+            }
             pressKey(Key.B)
         }
         rule.assertTyped("aABb")
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/KeyInjectionScope.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/KeyInjectionScope.kt
index c0758f4..3350296 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/KeyInjectionScope.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/KeyInjectionScope.kt
@@ -136,55 +136,6 @@
 }
 
 /**
- * Depresses each of the given [keys] sequentially, with [pauseDurationMillis] milliseconds
- * separating each successive call to [KeyInjectionScope.keyDown].
- *
- * If [keys] contains any duplicate elements, an [IllegalArgumentException] will be thrown.
- * If any of the given [keys] is already down, an [IllegalStateException] will be thrown.
- *
- * @param keys The keys to be depressed.
- * @param pauseDurationMillis The duration separating each key down event in milliseconds.
- */
-// TODO(b/234011835): Refactor this and all functions that take List<Keys> to use vararg instead.
-@ExperimentalTestApi
-fun KeyInjectionScope.keysDown(
-    keys: List<Key>,
-    pauseDurationMillis: Long = DefaultPauseDurationBetweenKeyPressesMillis
-) {
-    require(keys.size == keys.distinct().size) {
-        "List of keys must not contain any duplicates."
-    }
-    keys.forEachIndexed { idx: Int, key: Key ->
-        if (idx != 0) advanceEventTime(pauseDurationMillis)
-        keyDown(key)
-    }
-}
-
-/**
- * Releases each of the given [keys] sequentially, with [pauseDurationMillis] milliseconds
- * separating each successive call to [KeyInjectionScope.keyUp].
- *
- * If [keys] contains any duplicate elements, an [IllegalArgumentException] will be thrown.
- * If any of the given [keys] is not down, an [IllegalStateException] will be thrown.
- *
- * @param keys The keys to be released.
- * @param pauseDurationMillis The duration separating each key up event in milliseconds.
- */
-@ExperimentalTestApi
-fun KeyInjectionScope.keysUp(
-    keys: List<Key>,
-    pauseDurationMillis: Long = DefaultPauseDurationBetweenKeyPressesMillis
-) {
-    require(keys.size == keys.distinct().size) {
-        "List of keys must not contain any duplicates."
-    }
-    keys.forEachIndexed { idx: Int, key: Key ->
-        if (idx != 0) advanceEventTime(pauseDurationMillis)
-        keyUp(key)
-    }
-}
-
-/**
  * Holds down the given [key] for the given [pressDurationMillis] by sending a key down event,
  * advancing the event time and sending a key up event.
  *
@@ -204,144 +155,70 @@
 }
 
 /**
- * Presses the given [key] the given number of [times], for [pressDurationMillis] milliseconds each
- * time. Pauses for [pauseDurationMillis] milliseconds in between each key press.
- *
- * If the given [key] is already down an [IllegalStateException] is thrown.
- *
- * @param key The key to be pressed.
- * @param times The number of times to press the given key.
- * @param pressDurationMillis The length of time for which to hold each key press.
- * @param pauseDurationMillis The duration of the pause in between presses.
- */
-@ExperimentalTestApi
-fun KeyInjectionScope.pressKey(
-    key: Key,
-    times: Int,
-    pressDurationMillis: Long = DefaultKeyPressDurationMillis,
-    pauseDurationMillis: Long = DefaultPauseDurationBetweenKeyPressesMillis
-) = (0 until times).forEach { idx ->
-    if (idx != 0) advanceEventTime(pauseDurationMillis)
-    pressKey(key, pressDurationMillis)
-}
-
-/**
- * Holds down the key each of the given [keys] for the given [pressDurationMillis] in sequence, with
- * [pauseDurationMillis] milliseconds between each press.
- *
- * If one of the keys is already down, an [IllegalStateException] will be thrown.
- *
- * @param keys The list of keys to be pressed down.
- * @param pressDurationMillis Duration of press in milliseconds.
- * @param pauseDurationMillis The duration between presses.
- */
-@ExperimentalTestApi
-fun KeyInjectionScope.pressKeys(
-    keys: List<Key>,
-    pressDurationMillis: Long = DefaultKeyPressDurationMillis,
-    pauseDurationMillis: Long = DefaultPauseDurationBetweenKeyPressesMillis
-) = keys.forEachIndexed { idx: Int, key: Key ->
-    if (idx != 0) advanceEventTime(pauseDurationMillis)
-    pressKey(key, pressDurationMillis)
-}
-
-/**
  * Executes the keyboard sequence specified in the given [block], whilst holding down the
- * given [key]. This key must not be used within the [block]. Waits for [pauseDurationMillis]
- * milliseconds after pressing the [key] down before it injects the [block]. Waits for the same
- * duration after injecting the [block] before it releases the [key].
+ * given [key]. This key must not be used within the [block].
  *
  * If the given [key] is already down, an [IllegalStateException] will be thrown.
  *
  * @param key The key to be held down during injection of the [block].
- * @param pauseDurationMillis The pause after the initial key down and before the final key up.
  * @param block Sequence of KeyInjectionScope methods to be injected with the given key down.
  */
 @ExperimentalTestApi
-fun KeyInjectionScope.withKeyDown(
-    key: Key,
-    pauseDurationMillis: Long = DefaultPauseDurationBetweenKeyPressesMillis,
-    block: KeyInjectionScope.() -> Unit
-) {
+fun KeyInjectionScope.withKeyDown(key: Key, block: KeyInjectionScope.() -> Unit) {
     keyDown(key)
-    advanceEventTime(pauseDurationMillis)
     block.invoke(this)
-    advanceEventTime(pauseDurationMillis)
     keyUp(key)
 }
 
 /**
  * Executes the keyboard sequence specified in the given [block], whilst holding down the each of
- * the given [keys]. These keys must not be used within the [block]. Waits for [pauseDurationMillis]
- * milliseconds in between each key down and each key up event.
+ * the given [keys]. Each of the [keys] will be pressed down and released simultaneously.
+ * These keys must not be used within the [block].
  *
- * If [keys] contains any duplicate elements, an [IllegalArgumentException] will be thrown.
  * If any of the given [keys] are already down, an [IllegalStateException] will be thrown.
  *
  * @param keys List of keys to be held down during injection of the [block].
- * @param pauseDurationMillis The pause in milliseconds between each key down and key up event.
  * @param block Sequence of KeyInjectionScope methods to be injected with the given keys down.
  */
 @ExperimentalTestApi
-fun KeyInjectionScope.withKeysDown(
-    keys: List<Key>,
-    pauseDurationMillis: Long = DefaultPauseDurationBetweenKeyPressesMillis,
-    block: KeyInjectionScope.() -> Unit
-) {
-    keysDown(keys, pauseDurationMillis)
-    advanceEventTime(pauseDurationMillis)
+// TODO(b/234011835): Refactor this and all functions that take List<Keys> to use vararg instead.
+fun KeyInjectionScope.withKeysDown(keys: List<Key>, block: KeyInjectionScope.() -> Unit) {
+    keys.forEach { keyDown(it) }
     block.invoke(this)
-    advanceEventTime(pauseDurationMillis)
-    keysUp(keys, pauseDurationMillis)
+    keys.forEach { keyUp(it) }
 }
 
 /**
  * Executes the keyboard sequence specified in the given [block], in between presses to the
  * given [key]. This key can also be used within the [block], as long as it is not down at the end
- * of the block. There will be [pauseDurationMillis] milliseconds after the initial press and before
- * the final press.
+ * of the block.
  *
  * If the given [key] is already down, an [IllegalStateException] will be thrown.
  *
  * @param key The key to be toggled around the injection of the [block].
- * @param pauseDurationMillis The pause after the initial and before the final key presses.
  * @param block Sequence of KeyInjectionScope methods to be injected with the given key down.
  */
 @ExperimentalTestApi
-fun KeyInjectionScope.withKeyToggled(
-    key: Key,
-    pauseDurationMillis: Long = DefaultPauseDurationBetweenKeyPressesMillis,
-    block: KeyInjectionScope.() -> Unit
-) {
+fun KeyInjectionScope.withKeyToggled(key: Key, block: KeyInjectionScope.() -> Unit) {
     pressKey(key)
-    advanceEventTime(pauseDurationMillis)
     block.invoke(this)
-    advanceEventTime(pauseDurationMillis)
     pressKey(key)
 }
 
 /**
  * Executes the keyboard sequence specified in the given [block], in between presses to the
- * given [keys]. These keys can also be used within the [block], as long as they are not down at
- * the end of the block. There will be [pauseDurationMillis] milliseconds after the initial press
- * and before the final press.
+ * given [keys]. Each of the [keys] will be toggled simultaneously.These keys can also be used
+ * within the [block], as long as they are not down at the end of the block.
  *
  * If any of the given [keys] are already down, an [IllegalStateException] will be thrown.
  *
  * @param keys The keys to be toggled around the injection of the [block].
- * @param pauseDurationMillis The pause after the initial and before the final key presses.
  * @param block Sequence of KeyInjectionScope methods to be injected with the given keys down.
  */
 @ExperimentalTestApi
-fun KeyInjectionScope.withKeysToggled(
-    keys: List<Key>,
-    pauseDurationMillis: Long = DefaultPauseDurationBetweenKeyPressesMillis,
-    block: KeyInjectionScope.() -> Unit
-) {
+fun KeyInjectionScope.withKeysToggled(keys: List<Key>, block: KeyInjectionScope.() -> Unit) {
     pressKeys(keys)
-    advanceEventTime(pauseDurationMillis)
     block.invoke(this)
-    advanceEventTime(pauseDurationMillis)
     pressKeys(keys)
 }
 
@@ -404,3 +281,18 @@
 @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
 val KeyInjectionScope.isShiftDown: Boolean
     get() = isKeyDown(Key.ShiftLeft) || isKeyDown(Key.ShiftRight)
+
+/**
+ * Holds down the key each of the given [keys] for [DefaultKeyPressDurationMillis] in sequence, with
+ * [DefaultPauseDurationBetweenKeyPressesMillis] between each press.
+ *
+ * If one of the keys is already down, an [IllegalStateException] will be thrown.
+ *
+ * @param keys The list of keys to be pressed down.
+ */
+@ExperimentalTestApi
+private fun KeyInjectionScope.pressKeys(keys: List<Key>) =
+    keys.forEachIndexed { idx: Int, key: Key ->
+        if (idx != 0) advanceEventTime(DefaultPauseDurationBetweenKeyPressesMillis)
+        pressKey(key, DefaultKeyPressDurationMillis)
+    }
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index 4ac58e5..124c06b 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -398,11 +398,17 @@
     property public final long size;
   }
 
+  public final class TextMeasurerKt {
+  }
+
   public final class TextPainter {
     method public void paint(androidx.compose.ui.graphics.Canvas canvas, androidx.compose.ui.text.TextLayoutResult textLayoutResult);
     field public static final androidx.compose.ui.text.TextPainter INSTANCE;
   }
 
+  public final class TextPainterKt {
+  }
+
   @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class TextRange {
     method public operator boolean contains(long other);
     method public operator boolean contains(int offset);
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 ca406ac..fed7f60 100644
--- a/compose/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-text/api/public_plus_experimental_current.txt
@@ -464,11 +464,26 @@
     property public final long size;
   }
 
+  @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public final class TextMeasurer {
+    ctor public TextMeasurer(androidx.compose.ui.text.font.FontFamily.Resolver fallbackFontFamilyResolver, androidx.compose.ui.unit.Density fallbackDensity, androidx.compose.ui.unit.LayoutDirection fallbackLayoutDirection, optional int cacheSize);
+    method @androidx.compose.runtime.Stable public androidx.compose.ui.text.TextLayoutResult measure(androidx.compose.ui.text.AnnotatedString text, optional androidx.compose.ui.text.TextStyle style, optional int overflow, optional boolean softWrap, optional int maxLines, optional java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, optional long size, optional androidx.compose.ui.unit.LayoutDirection layoutDirection, optional androidx.compose.ui.unit.Density density, optional androidx.compose.ui.text.font.FontFamily.Resolver fontFamilyResolver, optional boolean skipCache);
+  }
+
+  public final class TextMeasurerKt {
+  }
+
   public final class TextPainter {
     method public void paint(androidx.compose.ui.graphics.Canvas canvas, androidx.compose.ui.text.TextLayoutResult textLayoutResult);
     field public static final androidx.compose.ui.text.TextPainter INSTANCE;
   }
 
+  public final class TextPainterKt {
+    method @androidx.compose.ui.text.ExperimentalTextApi public static void drawText(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.text.TextMeasurer textMeasurer, androidx.compose.ui.text.AnnotatedString text, optional long topLeft, optional androidx.compose.ui.text.TextStyle style, optional int overflow, optional boolean softWrap, optional int maxLines, optional java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, optional long size);
+    method @androidx.compose.ui.text.ExperimentalTextApi public static void drawText(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.text.TextMeasurer textMeasurer, String text, optional long topLeft, optional androidx.compose.ui.text.TextStyle style, optional int overflow, optional boolean softWrap, optional int maxLines, optional long size);
+    method @androidx.compose.ui.text.ExperimentalTextApi public static void drawText(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.text.TextLayoutResult textLayoutResult, optional long color, optional long topLeft, optional float alpha, optional androidx.compose.ui.graphics.Shadow? shadow, optional androidx.compose.ui.text.style.TextDecoration? textDecoration);
+    method @androidx.compose.ui.text.ExperimentalTextApi public static void drawText(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.text.TextLayoutResult textLayoutResult, androidx.compose.ui.graphics.Brush brush, optional long topLeft, optional float alpha, optional androidx.compose.ui.graphics.Shadow? shadow, optional androidx.compose.ui.text.style.TextDecoration? textDecoration);
+  }
+
   @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class TextRange {
     method public operator boolean contains(long other);
     method public operator boolean contains(int offset);
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index 4ac58e5..124c06b 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -398,11 +398,17 @@
     property public final long size;
   }
 
+  public final class TextMeasurerKt {
+  }
+
   public final class TextPainter {
     method public void paint(androidx.compose.ui.graphics.Canvas canvas, androidx.compose.ui.text.TextLayoutResult textLayoutResult);
     field public static final androidx.compose.ui.text.TextPainter INSTANCE;
   }
 
+  public final class TextPainterKt {
+  }
+
   @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class TextRange {
     method public operator boolean contains(long other);
     method public operator boolean contains(int offset);
diff --git a/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/TextMeasurerBenchmark.kt b/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/TextMeasurerBenchmark.kt
new file mode 100644
index 0000000..c72e982
--- /dev/null
+++ b/compose/ui/ui-text/benchmark/src/androidTest/java/androidx/compose/ui/text/benchmark/TextMeasurerBenchmark.kt
@@ -0,0 +1,133 @@
+/*
+ * 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.benchmark
+
+import android.content.Context
+import android.util.TypedValue
+import androidx.benchmark.junit4.BenchmarkRule
+import androidx.benchmark.junit4.measureRepeated
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.TextMeasurer
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.createFontFamilyResolver
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.sp
+import androidx.test.filters.LargeTest
+import androidx.test.platform.app.InstrumentationRegistry
+import kotlin.math.roundToInt
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@OptIn(ExperimentalTextApi::class)
+@LargeTest
+@RunWith(Parameterized::class)
+class TextMeasurerBenchmark(
+    private val textLength: Int,
+    private val textType: TextType,
+    alphabet: Alphabet
+) {
+    companion object {
+        @JvmStatic
+        @Parameterized.Parameters(name = "length={0} type={1} alphabet={2}")
+        fun initParameters(): List<Array<Any>> = cartesian(
+            arrayOf(8, 32, 128, 512),
+            arrayOf(TextType.PlainText, TextType.StyledText),
+            arrayOf(Alphabet.Latin, Alphabet.Cjk)
+        )
+    }
+
+    @get:Rule
+    val benchmarkRule = BenchmarkRule()
+
+    @get:Rule
+    val textBenchmarkRule = TextBenchmarkTestRule(alphabet)
+
+    private lateinit var instrumentationContext: Context
+
+    // Width initialized in setup().
+    private var width: Int = 0
+    private val fontSize = textBenchmarkRule.fontSizeSp.sp
+
+    @Before
+    fun setup() {
+        instrumentationContext = InstrumentationRegistry.getInstrumentation().context
+        width = TypedValue.applyDimension(
+            TypedValue.COMPLEX_UNIT_DIP,
+            textBenchmarkRule.widthDp,
+            instrumentationContext.resources.displayMetrics
+        ).roundToInt()
+    }
+
+    private fun text(textGenerator: RandomTextGenerator): AnnotatedString {
+        val text = textGenerator.nextParagraph(textLength)
+        val spanStyles = if (textType == TextType.StyledText) {
+            textGenerator.createStyles(text)
+        } else {
+            listOf()
+        }
+        return AnnotatedString(text = text, spanStyles = spanStyles)
+    }
+
+    @OptIn(ExperimentalTextApi::class)
+    @Test
+    fun text_measurer_no_cache() {
+        textBenchmarkRule.generator { textGenerator ->
+            val textMeasurer = TextMeasurer(
+                fallbackFontFamilyResolver = createFontFamilyResolver(instrumentationContext),
+                fallbackDensity = Density(instrumentationContext),
+                fallbackLayoutDirection = LayoutDirection.Ltr,
+                cacheSize = 0
+            )
+            val text = text(textGenerator)
+            benchmarkRule.measureRepeated {
+                textMeasurer.measure(
+                    text,
+                    style = TextStyle(color = Color.Red, fontSize = fontSize),
+                    size = IntSize(width, Int.MAX_VALUE)
+                )
+            }
+        }
+    }
+
+    @OptIn(ExperimentalTextApi::class)
+    @Test
+    fun text_measurer_cached() {
+        textBenchmarkRule.generator { textGenerator ->
+            val textMeasurer = TextMeasurer(
+                fallbackFontFamilyResolver = createFontFamilyResolver(instrumentationContext),
+                fallbackDensity = Density(instrumentationContext),
+                fallbackLayoutDirection = LayoutDirection.Ltr,
+                cacheSize = 16
+            )
+            val text = text(textGenerator)
+            benchmarkRule.measureRepeated {
+                textMeasurer.measure(
+                    text,
+                    style = TextStyle(color = Color.Red, fontSize = fontSize),
+                    size = IntSize(width, Int.MAX_VALUE)
+                )
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-text/lint-baseline.xml b/compose/ui/ui-text/lint-baseline.xml
index a05443f..af7ab19 100644
--- a/compose/ui/ui-text/lint-baseline.xml
+++ b/compose/ui/ui-text/lint-baseline.xml
@@ -1,14 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha01" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha01)" variant="all" version="7.4.0-alpha01">
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T> List&lt;T>.fastFilter(predicate: (T) -> Boolean): List&lt;T> {"
-        errorLine2="                                ~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/text/TempListUtils.kt"/>
-    </issue>
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="BanInlineOptIn"
@@ -31,514 +22,10 @@
     <issue
         id="BanInlineOptIn"
         message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, K> List&lt;T>.fastDistinctBy(selector: (T) -> K): List&lt;T> {"
-        errorLine2="                                   ~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/text/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
         errorLine1="internal inline fun &lt;T, R> List&lt;T>.fastZipWithNext(transform: (T, T) -> R): List&lt;R> {"
         errorLine2="                                   ~~~~~~~~~~~~~~~">
         <location
             file="../../../text/text/src/main/java/androidx/compose/ui/text/android/TempListUtils.kt"/>
     </issue>
 
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, R : Comparable&lt;R>> List&lt;T>.fastMinByOrNull(selector: (T) -> R): T? {"
-        errorLine2="                                                   ~~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/text/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, R> List&lt;T>.fastFold(initial: R, operation: (acc: R, T) -> R): R {"
-        errorLine2="                                   ~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/text/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, R> List&lt;T>.fastFlatMap(transform: (T) -> Iterable&lt;R>): List&lt;R> {"
-        errorLine2="                                   ~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/text/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T> List&lt;T>.fastFilterNot(predicate: (T) -> Boolean): List&lt;T> {"
-        errorLine2="                                ~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/text/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T> List&lt;T>.fastTakeWhile(predicate: (T) -> Boolean): List&lt;T> {"
-        errorLine2="                                ~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/text/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="    @OptIn(InternalPlatformTextApi::class, ExperimentalTextApi::class)"
-        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidFontListTypeface.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class, ExperimentalTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraphHelper.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraphIntrinsics.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraphIntrinsics.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraphIntrinsics.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/style/BaselineShiftSpan.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/BoringLayoutFactory.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/style/FontFeatureSpan.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/LayoutCompat.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/LayoutCompat.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/LayoutHelper.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/style/LetterSpacingSpanEm.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/style/LetterSpacingSpanPx.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/style/LineHeightSpan.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/style/LineHeightStyleSpan.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/PlaceholderExtensions.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/style/PlaceholderSpan.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentBreaker.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/animation/SegmentType.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/style/ShadowSpan.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/style/SkewXSpan.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class, ExperimentalTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/StaticLayoutFactory.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/style/TextDecorationSpan.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@OptIn(InternalPlatformTextApi::class)"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/TextLayout.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/style/TypefaceSpan.kt"/>
-    </issue>
-
-    <issue
-        id="NullAnnotationGroup"
-        message="Could not find associated group for annotation androidx.compose.ui.text.android.InternalPlatformTextApi, which is used in androidx.compose.ui."
-        errorLine1="@InternalPlatformTextApi"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="../../../text/text/src/main/java/androidx/compose/ui/text/android/selection/WordBoundary.kt"/>
-    </issue>
-
 </issues>
diff --git a/compose/ui/ui-text/samples/src/main/java/androidx/compose/ui/text/samples/DrawTextSamples.kt b/compose/ui/ui-text/samples/src/main/java/androidx/compose/ui/text/samples/DrawTextSamples.kt
new file mode 100644
index 0000000..e655120
--- /dev/null
+++ b/compose/ui/ui-text/samples/src/main/java/androidx/compose/ui/text/samples/DrawTextSamples.kt
@@ -0,0 +1,66 @@
+/*
+ * 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.samples
+
+import androidx.annotation.Sampled
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.drawText
+import androidx.compose.ui.text.rememberTextMeasurer
+import androidx.compose.ui.unit.sp
+
+@OptIn(ExperimentalTextApi::class)
+@Sampled
+@Composable
+fun DrawTextLayoutResultSample() {
+    val textMeasurer = rememberTextMeasurer()
+    var textLayoutResult by remember {
+        mutableStateOf<TextLayoutResult?>(null)
+    }
+
+    Canvas(
+        Modifier.fillMaxSize()
+            .layout { measurable, constraints ->
+                val placeable = measurable.measure(constraints)
+                // TextLayout can be done any time prior to its use in draw, including in a
+                // background thread.
+                // In this sample, text layout is done in compose layout. This way the layout call
+                // can be restarted when async font loading completes due to the fact that
+                // `.measure` call is executed in `.layout`.
+                textLayoutResult = textMeasurer.measure(
+                    text = AnnotatedString("Hello ".repeat(2)),
+                    style = TextStyle(fontSize = 35.sp)
+                )
+                layout(placeable.width, placeable.height) {
+                    placeable.placeRelative(0, 0)
+                }
+            }) {
+        // This happens during draw phase.
+        textLayoutResult?.let { drawText(it) }
+    }
+}
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/CacheTextLayoutInputTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/CacheTextLayoutInputTest.kt
new file mode 100644
index 0000000..d377ab3
--- /dev/null
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/CacheTextLayoutInputTest.kt
@@ -0,0 +1,230 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalTextApi::class)
+
+package androidx.compose.ui.text
+
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shadow
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.createFontFamilyResolver
+import androidx.compose.ui.text.style.TextDecoration
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.sp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class CacheTextLayoutInputTest {
+    private val context = InstrumentationRegistry.getInstrumentation().context
+    private val fontFamilyResolver = createFontFamilyResolver(context)
+
+    @Test
+    fun default_ctor_should_be_equal() {
+        val input1 = cacheTextLayoutInput()
+        val input2 = cacheTextLayoutInput()
+
+        assertThat(input1.hashCode()).isEqualTo(input2.hashCode())
+        assertThat(input1).isEqualTo(input2)
+    }
+
+    @Test
+    fun text_should_differ() {
+        val input1 = cacheTextLayoutInput(AnnotatedString("Hello"))
+        val input2 = cacheTextLayoutInput(AnnotatedString("Hello, World"))
+
+        assertThat(input1.hashCode()).isNotEqualTo(input2.hashCode())
+        assertThat(input1).isNotEqualTo(input2)
+    }
+
+    @Test
+    fun placeholders_should_differ() {
+        val input1 = cacheTextLayoutInput(placeholders = listOf(AnnotatedString.Range(
+            Placeholder(20.sp, 20.sp, PlaceholderVerticalAlign.AboveBaseline), 0, 1
+        )))
+        val input2 = cacheTextLayoutInput(placeholders = listOf(AnnotatedString.Range(
+            Placeholder(20.sp, 20.sp, PlaceholderVerticalAlign.AboveBaseline), 1, 2
+        )))
+
+        assertThat(input1.hashCode()).isNotEqualTo(input2.hashCode())
+        assertThat(input1).isNotEqualTo(input2)
+    }
+
+    @Test
+    fun maxLines_should_differ() {
+        val input1 = cacheTextLayoutInput(maxLines = 1)
+        val input2 = cacheTextLayoutInput(maxLines = 2)
+
+        assertThat(input1.hashCode()).isNotEqualTo(input2.hashCode())
+        assertThat(input1).isNotEqualTo(input2)
+    }
+
+    @Test
+    fun softWrap_should_differ() {
+        val input1 = cacheTextLayoutInput(softWrap = true)
+        val input2 = cacheTextLayoutInput(softWrap = false)
+
+        assertThat(input1.hashCode()).isNotEqualTo(input2.hashCode())
+        assertThat(input1).isNotEqualTo(input2)
+    }
+
+    @Test
+    fun overflow_should_differ() {
+        val input1 = cacheTextLayoutInput(overflow = TextOverflow.Visible)
+        val input2 = cacheTextLayoutInput(overflow = TextOverflow.Ellipsis)
+
+        assertThat(input1.hashCode()).isNotEqualTo(input2.hashCode())
+        assertThat(input1).isNotEqualTo(input2)
+    }
+
+    @Test
+    fun density_should_differ() {
+        val input1 = cacheTextLayoutInput(density = Density(1f))
+        val input2 = cacheTextLayoutInput(density = Density(1.5f))
+
+        assertThat(input1.hashCode()).isNotEqualTo(input2.hashCode())
+        assertThat(input1).isNotEqualTo(input2)
+    }
+
+    @Test
+    fun layoutDirection_should_differ() {
+        val input1 = cacheTextLayoutInput(layoutDirection = LayoutDirection.Ltr)
+        val input2 = cacheTextLayoutInput(layoutDirection = LayoutDirection.Rtl)
+
+        assertThat(input1.hashCode()).isNotEqualTo(input2.hashCode())
+        assertThat(input1).isNotEqualTo(input2)
+    }
+
+    @Test
+    fun fontFamilyResolver_should_differ() {
+        // FontFamilyResolver only checks for instance equality.
+        val input1 = cacheTextLayoutInput(fontFamilyResolver = createFontFamilyResolver(context))
+        val input2 = cacheTextLayoutInput(fontFamilyResolver = createFontFamilyResolver(context))
+
+        assertThat(input1.hashCode()).isNotEqualTo(input2.hashCode())
+        assertThat(input1).isNotEqualTo(input2)
+    }
+
+    @Test
+    fun constraints_maxWidth_should_differ() {
+        val input1 = cacheTextLayoutInput(constraints = Constraints(maxWidth = 100))
+        val input2 = cacheTextLayoutInput(constraints = Constraints(maxWidth = 200))
+
+        assertThat(input1.hashCode()).isNotEqualTo(input2.hashCode())
+        assertThat(input1).isNotEqualTo(input2)
+    }
+
+    @Test
+    fun constraints_maxHeight_should_differ() {
+        val input1 = cacheTextLayoutInput(constraints = Constraints(maxHeight = 100))
+        val input2 = cacheTextLayoutInput(constraints = Constraints(maxHeight = 200))
+
+        assertThat(input1.hashCode()).isNotEqualTo(input2.hashCode())
+        assertThat(input1).isNotEqualTo(input2)
+    }
+
+    @Test
+    fun color_should_not_differ() {
+        val input1 = cacheTextLayoutInput(style = TextStyle(color = Color.Red))
+        val input2 = cacheTextLayoutInput(style = TextStyle(color = Color.Blue))
+
+        assertThat(input1.hashCode()).isEqualTo(input2.hashCode())
+        assertThat(input1).isEqualTo(input2)
+    }
+
+    @Test
+    fun brush_should_not_differ() {
+        val input1 = cacheTextLayoutInput(style = TextStyle(color = Color.Red))
+        val input2 = cacheTextLayoutInput(style = TextStyle(brush = SolidColor(Color.Blue)))
+
+        assertThat(input1.hashCode()).isEqualTo(input2.hashCode())
+        assertThat(input1).isEqualTo(input2)
+    }
+
+    @Test
+    fun shadow_should_not_differ() {
+        val input1 = cacheTextLayoutInput(
+            style = TextStyle(shadow = Shadow(Color.Red, Offset(10f, 10f)))
+        )
+        val input2 = cacheTextLayoutInput(
+            style = TextStyle(shadow = Shadow(Color.Red, Offset(12f, 12f)))
+        )
+
+        assertThat(input1.hashCode()).isEqualTo(input2.hashCode())
+        assertThat(input1).isEqualTo(input2)
+    }
+
+    @Test
+    fun textDecoration_should_not_differ() {
+        val input1 = cacheTextLayoutInput(
+            style = TextStyle(textDecoration = TextDecoration.Underline)
+        )
+        val input2 = cacheTextLayoutInput(
+            style = TextStyle(textDecoration = TextDecoration.LineThrough)
+        )
+
+        assertThat(input1.hashCode()).isEqualTo(input2.hashCode())
+        assertThat(input1).isEqualTo(input2)
+    }
+
+    @Test
+    fun minConstraints_should_not_differ() {
+        val input1 = cacheTextLayoutInput(constraints = Constraints(minWidth = 10, minHeight = 20))
+        val input2 = cacheTextLayoutInput(constraints = Constraints(minWidth = 20, minHeight = 10))
+
+        assertThat(input1.hashCode()).isEqualTo(input2.hashCode())
+        assertThat(input1).isEqualTo(input2)
+    }
+
+    private fun cacheTextLayoutInput(
+        text: AnnotatedString = AnnotatedString("Hello"),
+        style: TextStyle = TextStyle.Default,
+        placeholders: List<AnnotatedString.Range<Placeholder>> = emptyList(),
+        maxLines: Int = Int.MAX_VALUE,
+        softWrap: Boolean = true,
+        overflow: TextOverflow = TextOverflow.Clip,
+        density: Density = Density(context),
+        layoutDirection: LayoutDirection = LayoutDirection.Ltr,
+        fontFamilyResolver: FontFamily.Resolver = this.fontFamilyResolver,
+        constraints: Constraints = Constraints()
+    ): CacheTextLayoutInput {
+        return CacheTextLayoutInput(
+            TextLayoutInput(
+                text = text,
+                style = style,
+                placeholders = placeholders,
+                maxLines = maxLines,
+                softWrap = softWrap,
+                overflow = overflow,
+                density = density,
+                layoutDirection = layoutDirection,
+                fontFamilyResolver = fontFamilyResolver,
+                constraints = constraints
+            )
+        )
+    }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextLayoutCacheTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextLayoutCacheTest.kt
new file mode 100644
index 0000000..43cbe84
--- /dev/null
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextLayoutCacheTest.kt
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalTextApi::class)
+
+package androidx.compose.ui.text
+
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shadow
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.createFontFamilyResolver
+import androidx.compose.ui.text.font.toFontFamily
+import androidx.compose.ui.text.style.TextDecoration
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.sp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class TextLayoutCacheTest {
+    private val fontFamilyMeasureFont = FontTestData.BASIC_MEASURE_FONT.toFontFamily()
+    private val context = InstrumentationRegistry.getInstrumentation().context
+    private val fontFamilyResolver = createFontFamilyResolver(context)
+    private val defaultDensity = Density(density = 1f)
+
+    @Test(expected = IllegalArgumentException::class)
+    fun capacity_cannot_be_zero() {
+        TextLayoutCache(0)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun capacity_cannot_be_negative() {
+        TextLayoutCache(-2)
+    }
+
+    @Test
+    fun exactInput_shouldReturnTheSameResult() {
+        val textLayoutCache = TextLayoutCache(16)
+        val textLayoutInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(color = Color.Red)
+        )
+
+        val textLayoutResult = layoutText(textLayoutInput)
+        textLayoutCache.put(textLayoutInput, textLayoutResult)
+
+        Truth.assertThat(textLayoutCache.get(textLayoutInput)).isEqualTo(textLayoutResult)
+    }
+
+    @Test
+    fun colorChange_shouldReturnFromCache() {
+        val textLayoutCache = TextLayoutCache(16)
+        val firstInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(color = Color.Red)
+        )
+
+        val secondInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(color = Color.Blue)
+        )
+
+        val textLayoutResult = layoutText(firstInput)
+        textLayoutCache.put(firstInput, textLayoutResult)
+
+        Truth.assertThat(textLayoutCache.get(secondInput)).isEqualTo(textLayoutResult)
+    }
+
+    @Test
+    fun brushChange_shouldReturnFromCache() {
+        val textLayoutCache = TextLayoutCache(16)
+        val firstInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(color = Color.Red)
+        )
+
+        val secondInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(brush = Brush.linearGradient(listOf(Color.Blue, Color.Red)))
+        )
+
+        val textLayoutResult = layoutText(firstInput)
+        textLayoutCache.put(firstInput, textLayoutResult)
+
+        Truth.assertThat(textLayoutCache.get(secondInput)).isEqualTo(textLayoutResult)
+    }
+
+    @Test
+    fun shadowChange_shouldReturnFromCache() {
+        val textLayoutCache = TextLayoutCache(16)
+        val firstInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(shadow = Shadow(color = Color.Red))
+        )
+
+        val secondInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(shadow = Shadow(color = Color.Blue))
+        )
+
+        val textLayoutResult = layoutText(firstInput)
+        textLayoutCache.put(firstInput, textLayoutResult)
+
+        Truth.assertThat(textLayoutCache.get(secondInput)).isEqualTo(textLayoutResult)
+    }
+
+    @Test
+    fun textDecorationChange_shouldReturnFromCache() {
+        val textLayoutCache = TextLayoutCache(16)
+        val firstInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(textDecoration = TextDecoration.LineThrough)
+        )
+
+        val secondInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(textDecoration = TextDecoration.Underline)
+        )
+
+        val textLayoutResult = layoutText(firstInput)
+        textLayoutCache.put(firstInput, textLayoutResult)
+
+        Truth.assertThat(textLayoutCache.get(secondInput)).isEqualTo(textLayoutResult)
+    }
+
+    @Test
+    fun constraintsMinChanges_shouldReturnFromCache() {
+        val textLayoutCache = TextLayoutCache(16)
+        val firstInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(color = Color.Red),
+            constraints = Constraints(minWidth = 20, maxWidth = 200)
+        )
+
+        val secondInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(color = Color.Red),
+            constraints = Constraints(minWidth = 60, maxWidth = 200)
+        )
+
+        val textLayoutResult = layoutText(firstInput)
+        textLayoutCache.put(firstInput, textLayoutResult)
+
+        Truth.assertThat(textLayoutCache.get(secondInput)).isEqualTo(textLayoutResult)
+    }
+
+    @Test
+    fun textChanges_shouldReturnNull() {
+        val textLayoutCache = TextLayoutCache(16)
+        val firstInput = textLayoutInput(text = AnnotatedString("Hello World"))
+
+        val secondInput = textLayoutInput(text = AnnotatedString("Hello World!"))
+
+        val textLayoutResult = layoutText(firstInput)
+        textLayoutCache.put(firstInput, textLayoutResult)
+
+        Truth.assertThat(textLayoutCache.get(secondInput)).isNull()
+    }
+
+    @Test
+    fun fontSizeChange_shouldReturnNull() {
+        val textLayoutCache = TextLayoutCache(16)
+        val firstInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(color = Color.Red, fontSize = 14.sp)
+        )
+
+        val secondInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(color = Color.Red, fontSize = 18.sp)
+        )
+
+        val textLayoutResult = layoutText(firstInput)
+        textLayoutCache.put(firstInput, textLayoutResult)
+
+        Truth.assertThat(textLayoutCache.get(secondInput)).isNull()
+    }
+
+    @Test
+    fun densityChange_shouldReturnNull() {
+        val textLayoutCache = TextLayoutCache(16)
+        val firstInput = textLayoutInput(
+            text = AnnotatedString("Hello")
+        )
+
+        val secondInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            density = Density(2f)
+        )
+
+        val textLayoutResult = layoutText(firstInput)
+        textLayoutCache.put(firstInput, textLayoutResult)
+
+        Truth.assertThat(textLayoutCache.get(secondInput)).isNull()
+    }
+
+    @Test
+    fun layoutDirectionChange_shouldReturnNull() {
+        val textLayoutCache = TextLayoutCache(16)
+        val firstInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            layoutDirection = LayoutDirection.Ltr
+        )
+
+        val secondInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            layoutDirection = LayoutDirection.Rtl
+        )
+
+        val textLayoutResult = layoutText(firstInput)
+        textLayoutCache.put(firstInput, textLayoutResult)
+
+        Truth.assertThat(textLayoutCache.get(secondInput)).isNull()
+    }
+
+    @Test
+    fun constraintsMaxChanges_shouldReturnNull() {
+        val textLayoutCache = TextLayoutCache(16)
+        val firstInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(color = Color.Red),
+            constraints = Constraints(minWidth = 20, maxWidth = 200)
+        )
+
+        val secondInput = textLayoutInput(
+            text = AnnotatedString("Hello"),
+            style = TextStyle(color = Color.Red),
+            constraints = Constraints(minWidth = 20, maxWidth = 250)
+        )
+
+        val textLayoutResult = layoutText(firstInput)
+        textLayoutCache.put(firstInput, textLayoutResult)
+
+        Truth.assertThat(textLayoutCache.get(secondInput)).isNull()
+    }
+
+    @Test
+    fun cacheShouldEvict_leastRecentlyUsedLayout() {
+        val textLayoutCache = TextLayoutCache(2)
+        val firstInput = textLayoutInput(text = AnnotatedString("1"))
+        val secondInput = textLayoutInput(text = AnnotatedString("2"))
+        val thirdInput = textLayoutInput(text = AnnotatedString("3"))
+
+        val firstLayout = layoutText(firstInput)
+        val secondLayout = layoutText(secondInput)
+        val thirdLayout = layoutText(thirdInput)
+
+        textLayoutCache.put(firstInput, firstLayout)
+        textLayoutCache.put(secondInput, secondLayout)
+        textLayoutCache.get(firstInput)
+        textLayoutCache.put(thirdInput, thirdLayout)
+
+        Truth.assertThat(textLayoutCache.get(firstInput)).isNotNull()
+        Truth.assertThat(textLayoutCache.get(secondInput)).isNull()
+        Truth.assertThat(textLayoutCache.get(thirdInput)).isNotNull()
+    }
+
+    private fun textLayoutInput(
+        text: AnnotatedString,
+        style: TextStyle = TextStyle.Default,
+        placeholders: List<AnnotatedString.Range<Placeholder>> = emptyList(),
+        maxLines: Int = Int.MAX_VALUE,
+        softWrap: Boolean = true,
+        overflow: TextOverflow = TextOverflow.Clip,
+        density: Density = this.defaultDensity,
+        layoutDirection: LayoutDirection = LayoutDirection.Ltr,
+        fontFamilyResolver: FontFamily.Resolver = this.fontFamilyResolver,
+        constraints: Constraints = Constraints()
+    ): TextLayoutInput {
+        return TextLayoutInput(
+            text = text,
+            style = style.merge(TextStyle(fontFamily = fontFamilyMeasureFont)),
+            placeholders = placeholders,
+            maxLines = maxLines,
+            softWrap = softWrap,
+            overflow = overflow,
+            density = density,
+            layoutDirection = layoutDirection,
+            fontFamilyResolver = fontFamilyResolver,
+            constraints = constraints
+        )
+    }
+
+    private fun layoutText(textLayoutInput: TextLayoutInput) = with(textLayoutInput) {
+        val measurer = TextMeasurer(
+            fontFamilyResolver,
+            density,
+            layoutDirection,
+            0
+        )
+        measurer.measure(
+            text = text,
+            style = style,
+            overflow = overflow,
+            softWrap = softWrap,
+            maxLines = maxLines,
+            placeholders = placeholders,
+            size = IntSize(constraints.maxWidth, constraints.maxHeight),
+        )
+    }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextMeasurerTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextMeasurerTest.kt
new file mode 100644
index 0000000..db5ab99
--- /dev/null
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextMeasurerTest.kt
@@ -0,0 +1,337 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalTextApi::class)
+
+package androidx.compose.ui.text
+
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shadow
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.createFontFamilyResolver
+import androidx.compose.ui.text.font.toFontFamily
+import androidx.compose.ui.text.style.TextDecoration
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class TextMeasurerTest {
+    private val fontFamilyMeasureFont = FontTestData.BASIC_MEASURE_FONT.toFontFamily()
+    private val context = InstrumentationRegistry.getInstrumentation().context
+    private val fontFamilyResolver = createFontFamilyResolver(context)
+    private val defaultDensity = Density(density = 1f)
+    private val layoutDirection = LayoutDirection.Ltr
+
+    private val longText = AnnotatedString(
+        "Lorem ipsum dolor sit amet, consectetur " +
+            "adipiscing elit. Curabitur augue leo, finibus vitae felis ac, pretium condimentum " +
+            "augue. Nullam non libero sed lectus aliquet venenatis non at purus. Fusce id arcu " +
+            "eu mauris pulvinar laoreet."
+    )
+
+    private val multiLineText = AnnotatedString("Lorem\nipsum\ndolor\nsit\namet")
+
+    @Test
+    fun width_shouldMatter_ifSoftwrapIsEnabled() {
+        val textLayoutResult = layoutText(
+            textLayoutInput(
+                text = longText,
+                softWrap = true,
+                constraints = Constraints(maxWidth = 200)
+            )
+        )
+
+        assertThat(textLayoutResult.multiParagraph.width).isEqualTo(200)
+    }
+
+    @Test
+    fun width_shouldMatter_ifSoftwrapIsDisabled_butOverflowIsEllipsis() {
+        val textLayoutResult = layoutText(
+            textLayoutInput(
+                text = longText,
+                softWrap = false,
+                overflow = TextOverflow.Ellipsis,
+                constraints = Constraints(maxWidth = 200)
+            )
+        )
+
+        assertThat(textLayoutResult.multiParagraph.width).isEqualTo(200)
+    }
+
+    @Test
+    fun width_shouldBeMaxIntrinsicWidth_ifSoftwrapIsDisabled_andOverflowIsClip() {
+        val textLayoutResult = layoutText(
+            textLayoutInput(
+                text = longText,
+                softWrap = false,
+                overflow = TextOverflow.Clip,
+                constraints = Constraints(maxWidth = 200)
+            )
+        )
+
+        val intrinsics = multiParagraphIntrinsics(text = longText)
+
+        assertThat(textLayoutResult.multiParagraph.width).isEqualTo(intrinsics.maxIntrinsicWidth)
+    }
+
+    @Test
+    fun width_shouldBeMaxIntrinsicWidth_ifSoftwrapIsDisabled_andOverflowIsVisible() {
+        val textLayoutResult = layoutText(
+            textLayoutInput(
+                text = longText,
+                softWrap = false,
+                overflow = TextOverflow.Clip,
+                constraints = Constraints(maxWidth = 200)
+            )
+        )
+
+        val intrinsics = multiParagraphIntrinsics(text = longText)
+
+        assertThat(textLayoutResult.multiParagraph.width).isEqualTo(intrinsics.maxIntrinsicWidth)
+    }
+
+    @Test
+    fun overwriteMaxLines_ifSoftwrapIsDisabled_andTextOverflowIsEllipsis() {
+        val textLayoutResult = layoutText(
+            textLayoutInput(
+                text = multiLineText,
+                softWrap = false,
+                overflow = TextOverflow.Ellipsis
+            )
+        )
+
+        assertThat(textLayoutResult.multiParagraph.lineCount).isEqualTo(1)
+    }
+
+    @Test
+    fun dontOverwriteMaxLines_ifSoftwrapIsEnabled() {
+        val textLayoutResult = layoutText(
+            textLayoutInput(
+                text = multiLineText,
+                softWrap = true,
+                overflow = TextOverflow.Ellipsis
+            )
+        )
+
+        assertThat(textLayoutResult.multiParagraph.lineCount).isEqualTo(5)
+    }
+
+    @Test
+    fun disabledSoftwrap_andOverflowClip_shouldConstrainLayoutSize() {
+        val textLayoutResult = layoutText(
+            textLayoutInput(
+                text = longText,
+                softWrap = false,
+                overflow = TextOverflow.Clip,
+                constraints = Constraints(maxWidth = 200)
+            )
+        )
+
+        assertThat(textLayoutResult.multiParagraph.width).isNotEqualTo(200f)
+        assertThat(textLayoutResult.size.width).isEqualTo(200)
+    }
+
+    @Test
+    fun disabledSoftwrap_andOverflowVisible_shouldConstrainLayoutSize() {
+        val textLayoutResult = layoutText(
+            textLayoutInput(
+                text = longText,
+                softWrap = false,
+                overflow = TextOverflow.Clip,
+                constraints = Constraints(maxWidth = 200)
+            )
+        )
+
+        assertThat(textLayoutResult.multiParagraph.width).isNotEqualTo(200f)
+        assertThat(textLayoutResult.size.width).isEqualTo(200)
+    }
+
+    @Test
+    fun colorShouldChangeInResult_whenCacheIsActive() {
+        val textMeasurer = textMeasurer(cacheSize = 8)
+        val firstTextLayout = layoutText(
+            textLayoutInput(
+                text = longText,
+                style = TextStyle(color = Color.Red)
+            ), textMeasurer
+        )
+
+        val secondTextLayout = layoutText(
+            textLayoutInput(
+                text = longText,
+                style = TextStyle(color = Color.Blue)
+            ), textMeasurer
+        )
+
+        assertThat(firstTextLayout.multiParagraph).isSameInstanceAs(secondTextLayout.multiParagraph)
+        assertThat(firstTextLayout.layoutInput.style.color).isEqualTo(Color.Red)
+        assertThat(secondTextLayout.layoutInput.style.color).isEqualTo(Color.Blue)
+    }
+
+    @Test
+    fun brushShouldChangeInResult_whenCacheIsActive() {
+        val textMeasurer = textMeasurer(cacheSize = 8)
+        val firstTextLayout = layoutText(
+            textLayoutInput(
+                text = longText,
+                style = TextStyle(brush = Brush.linearGradient(listOf(Color.Red, Color.Blue)))
+            ), textMeasurer
+        )
+
+        val secondTextLayout = layoutText(
+            textLayoutInput(
+                text = longText,
+                style = TextStyle(brush = Brush.linearGradient(listOf(Color.Green, Color.Yellow)))
+            ), textMeasurer
+        )
+
+        assertThat(firstTextLayout.multiParagraph).isSameInstanceAs(secondTextLayout.multiParagraph)
+        assertThat(firstTextLayout.layoutInput.style.brush)
+            .isEqualTo(Brush.linearGradient(listOf(Color.Red, Color.Blue)))
+        assertThat(secondTextLayout.layoutInput.style.brush)
+            .isEqualTo(Brush.linearGradient(listOf(Color.Green, Color.Yellow)))
+    }
+
+    @Test
+    fun shadowShouldChangeInResult_whenCacheIsActive() {
+        val textMeasurer = textMeasurer(cacheSize = 8)
+        val firstTextLayout = layoutText(
+            textLayoutInput(
+                text = longText,
+                style = TextStyle(shadow = Shadow(Color.Red))
+            ), textMeasurer
+        )
+
+        val secondTextLayout = layoutText(
+            textLayoutInput(
+                text = longText,
+                style = TextStyle(shadow = Shadow(Color.Blue))
+            ), textMeasurer
+        )
+
+        assertThat(firstTextLayout.multiParagraph).isSameInstanceAs(secondTextLayout.multiParagraph)
+        assertThat(firstTextLayout.layoutInput.style.shadow).isEqualTo(Shadow(Color.Red))
+        assertThat(secondTextLayout.layoutInput.style.shadow).isEqualTo(Shadow(Color.Blue))
+    }
+
+    @Test
+    fun textDecorationShouldChangeInResult_whenCacheIsActive() {
+        val textMeasurer = textMeasurer(cacheSize = 8)
+        val firstTextLayout = layoutText(
+            textLayoutInput(
+                text = longText,
+                style = TextStyle(textDecoration = TextDecoration.Underline)
+            ), textMeasurer
+        )
+
+        val secondTextLayout = layoutText(
+            textLayoutInput(
+                text = longText,
+                style = TextStyle(textDecoration = TextDecoration.LineThrough)
+            ), textMeasurer
+        )
+
+        assertThat(firstTextLayout.multiParagraph).isSameInstanceAs(secondTextLayout.multiParagraph)
+        assertThat(firstTextLayout.layoutInput.style.textDecoration)
+            .isEqualTo(TextDecoration.Underline)
+        assertThat(secondTextLayout.layoutInput.style.textDecoration)
+            .isEqualTo(TextDecoration.LineThrough)
+    }
+
+    private fun textLayoutInput(
+        text: AnnotatedString = AnnotatedString("Hello"),
+        style: TextStyle = TextStyle.Default,
+        placeholders: List<AnnotatedString.Range<Placeholder>> = emptyList(),
+        maxLines: Int = Int.MAX_VALUE,
+        softWrap: Boolean = true,
+        overflow: TextOverflow = TextOverflow.Clip,
+        density: Density = this.defaultDensity,
+        layoutDirection: LayoutDirection = this.layoutDirection,
+        fontFamilyResolver: FontFamily.Resolver = this.fontFamilyResolver,
+        constraints: Constraints = Constraints()
+    ): TextLayoutInput {
+        return TextLayoutInput(
+            text = text,
+            style = style.merge(TextStyle(fontFamily = fontFamilyMeasureFont)),
+            placeholders = placeholders,
+            maxLines = maxLines,
+            softWrap = softWrap,
+            overflow = overflow,
+            density = density,
+            layoutDirection = layoutDirection,
+            fontFamilyResolver = fontFamilyResolver,
+            constraints = constraints
+        )
+    }
+
+    private fun multiParagraphIntrinsics(
+        text: AnnotatedString = AnnotatedString("Hello"),
+        style: TextStyle = TextStyle.Default,
+        placeholders: List<AnnotatedString.Range<Placeholder>> = emptyList(),
+        density: Density = this.defaultDensity,
+        layoutDirection: LayoutDirection = this.layoutDirection,
+        fontFamilyResolver: FontFamily.Resolver = this.fontFamilyResolver
+    ): MultiParagraphIntrinsics {
+        return MultiParagraphIntrinsics(
+            annotatedString = text,
+            style = resolveDefaults(
+                style.merge(TextStyle(fontFamily = fontFamilyMeasureFont)),
+                layoutDirection
+            ),
+            placeholders = placeholders,
+            density = density,
+            fontFamilyResolver = fontFamilyResolver
+        )
+    }
+
+    private fun textMeasurer(
+        fontFamilyResolver: FontFamily.Resolver = this.fontFamilyResolver,
+        density: Density = this.defaultDensity,
+        layoutDirection: LayoutDirection = this.layoutDirection,
+        cacheSize: Int = 0
+    ): TextMeasurer = TextMeasurer(
+        fontFamilyResolver,
+        density,
+        layoutDirection,
+        cacheSize
+    )
+
+    private fun layoutText(
+        textLayoutInput: TextLayoutInput,
+        textMeasurer: TextMeasurer? = null
+    ) = with(textLayoutInput) {
+        (textMeasurer ?: textMeasurer()).measure(
+            text = text,
+            style = style,
+            overflow = overflow,
+            softWrap = softWrap,
+            maxLines = maxLines,
+            placeholders = placeholders,
+            size = IntSize(constraints.maxWidth, constraints.maxHeight),
+        )
+    }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextPainterTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextPainterTest.kt
new file mode 100644
index 0000000..ea43dc0
--- /dev/null
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextPainterTest.kt
@@ -0,0 +1,366 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalTextApi::class)
+
+package androidx.compose.ui.text
+
+import android.graphics.Bitmap
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Canvas
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.drawscope.CanvasDrawScope
+import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.createFontFamilyResolver
+import androidx.compose.ui.text.font.toFontFamily
+import androidx.compose.ui.text.matchers.assertThat
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.sp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@MediumTest
+class TextPainterTest {
+
+    private val fontFamilyMeasureFont = FontTestData.BASIC_MEASURE_FONT.toFontFamily()
+    private val context = InstrumentationRegistry.getInstrumentation().context
+    private val fontFamilyResolver = createFontFamilyResolver(context)
+    private var defaultDensity = Density(density = 1f)
+    private var layoutDirection = LayoutDirection.Ltr
+
+    private val longText = AnnotatedString(
+        "Lorem ipsum dolor sit amet, consectetur " +
+            "adipiscing elit. Curabitur augue leo, finibus vitae felis ac, pretium condimentum " +
+            "augue. Nullam non libero sed lectus aliquet venenatis non at purus. Fusce id arcu " +
+            "eu mauris pulvinar laoreet."
+    )
+
+    @Test
+    fun drawTextWithMeasurer_shouldBeEqualTo_drawTextLayoutResult() {
+        val measurer = textMeasurer()
+        val textLayoutResult = measurer.measure(
+            text = longText,
+            style = TextStyle(fontFamily = fontFamilyMeasureFont, fontSize = 20.sp),
+            size = IntSize(400, 400)
+        )
+
+        val bitmap = draw {
+            drawText(textLayoutResult)
+        }
+        val bitmap2 = draw {
+            drawText(
+                measurer,
+                text = longText,
+                style = TextStyle(fontFamily = fontFamilyMeasureFont, fontSize = 20.sp),
+                size = IntSize(400, 400)
+            )
+        }
+
+        assertThat(bitmap).isEqualToBitmap(bitmap2)
+    }
+
+    @Test
+    fun textMeasurerCache_shouldNotAffectTheResult_forColor() {
+        val measurer = textMeasurer(cacheSize = 8)
+
+        val bitmap = draw {
+            drawText(
+                textMeasurer = measurer,
+                text = longText,
+                style = TextStyle(
+                    color = Color.Red,
+                    fontFamily = fontFamilyMeasureFont,
+                    fontSize = 20.sp
+                ),
+                size = IntSize(400, 400)
+            )
+        }
+        val bitmap2 = draw {
+            drawText(
+                textMeasurer = measurer,
+                text = longText,
+                style = TextStyle(
+                    color = Color.Blue,
+                    fontFamily = fontFamilyMeasureFont,
+                    fontSize = 20.sp
+                ),
+                size = IntSize(400, 400)
+            )
+        }
+
+        assertThat(bitmap).isNotEqualToBitmap(bitmap2)
+    }
+
+    @Test
+    fun textMeasurerCache_shouldNotAffectTheResult_forFontSize() {
+        val measurer = textMeasurer(cacheSize = 8)
+
+        val bitmap = draw {
+            drawText(
+                textMeasurer = measurer,
+                text = longText,
+                style = TextStyle(fontFamily = fontFamilyMeasureFont, fontSize = 20.sp),
+                size = IntSize(400, 400)
+            )
+        }
+        val bitmap2 = draw {
+            drawText(
+                textMeasurer = measurer,
+                text = longText,
+                style = TextStyle(fontFamily = fontFamilyMeasureFont, fontSize = 24.sp),
+                size = IntSize(400, 400)
+            )
+        }
+
+        assertThat(bitmap).isNotEqualToBitmap(bitmap2)
+    }
+
+    @Test
+    fun drawTextLayout_shouldChangeColor() {
+        val measurer = textMeasurer()
+        val textLayoutResultRed = measurer.measure(
+            text = longText,
+            style = TextStyle(
+                color = Color.Red,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ),
+            size = IntSize(400, 400)
+        )
+
+        val textLayoutResultBlue = measurer.measure(
+            text = longText,
+            style = TextStyle(
+                color = Color.Blue,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ),
+            size = IntSize(400, 400)
+        )
+
+        val bitmap = draw {
+            drawText(textLayoutResultRed, color = Color.Blue)
+        }
+        val bitmap2 = draw {
+            drawText(textLayoutResultBlue)
+        }
+
+        assertThat(bitmap).isEqualToBitmap(bitmap2)
+    }
+
+    @Test
+    fun drawTextLayout_shouldChangeAlphaColor() {
+        val measurer = textMeasurer()
+        val textLayoutResultOpaque = measurer.measure(
+            text = longText,
+            style = TextStyle(
+                color = Color.Red,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ),
+            size = IntSize(400, 400)
+        )
+
+        val textLayoutResultHalfOpaque = measurer.measure(
+            text = longText,
+            style = TextStyle(
+                color = Color.Red.copy(alpha = 0.5f),
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ),
+            size = IntSize(400, 400)
+        )
+
+        val bitmap = draw {
+            drawText(textLayoutResultOpaque, alpha = 0.5f)
+        }
+        val bitmap2 = draw {
+            drawText(textLayoutResultHalfOpaque)
+        }
+
+        assertThat(bitmap).isEqualToBitmap(bitmap2)
+    }
+
+    @Test
+    fun drawTextLayout_shouldChangeBrush() {
+        val rbBrush = Brush.radialGradient(listOf(Color.Red, Color.Blue))
+        val gyBrush = Brush.radialGradient(listOf(Color.Green, Color.Yellow))
+        val measurer = textMeasurer()
+        val textLayoutResultRB = measurer.measure(
+            text = longText,
+            style = TextStyle(
+                brush = rbBrush,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ),
+            size = IntSize(400, 400)
+        )
+
+        val textLayoutResultGY = measurer.measure(
+            text = longText,
+            style = TextStyle(
+                brush = gyBrush,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ),
+            size = IntSize(400, 400)
+        )
+
+        val bitmap = draw {
+            drawText(textLayoutResultRB, brush = gyBrush)
+        }
+        val bitmap2 = draw {
+            drawText(textLayoutResultGY)
+        }
+
+        assertThat(bitmap).isEqualToBitmap(bitmap2)
+    }
+
+    @Test
+    fun drawTextLayout_shouldChangeAlphaForBrush() {
+        val rbBrush = Brush.radialGradient(listOf(Color.Red, Color.Blue))
+        val measurer = textMeasurer()
+        val textLayoutResultOpaque = measurer.measure(
+            text = longText,
+            style = TextStyle(
+                brush = rbBrush,
+                alpha = 1f,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ),
+            size = IntSize(400, 400)
+        )
+
+        val textLayoutResultHalfOpaque = measurer.measure(
+            text = longText,
+            style = TextStyle(
+                brush = rbBrush,
+                alpha = 0.5f,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ),
+            size = IntSize(400, 400)
+        )
+
+        val bitmap = draw {
+            drawText(textLayoutResultOpaque, alpha = 0.5f)
+        }
+        val bitmap2 = draw {
+            drawText(textLayoutResultHalfOpaque)
+        }
+
+        assertThat(bitmap).isEqualToBitmap(bitmap2)
+    }
+
+    @Test
+    fun textMeasurerDraw_isConstrainedTo_canvasSizeByDefault() {
+        val measurer = textMeasurer()
+        // constrain the width, height is ignored
+        val textLayoutResult = measurer.measure(
+            text = longText,
+            style = TextStyle(
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ),
+            size = IntSize(200, 4000)
+        )
+
+        val bitmap = draw(200f, 4000f) {
+            drawText(textLayoutResult)
+        }
+        val bitmap2 = draw(200f, 4000f) {
+            drawText(measurer, longText, style = TextStyle(
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ))
+        }
+
+        assertThat(bitmap).isEqualToBitmap(bitmap2)
+    }
+
+    @Test
+    fun textMeasurerDraw_usesCanvasDensity_ByDefault() {
+        val measurer = textMeasurer()
+        // constrain the width, height is ignored
+        val textLayoutResult = measurer.measure(
+            text = longText,
+            style = TextStyle(
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ),
+            density = Density(4f),
+            size = IntSize(1000, 1000)
+        )
+
+        val bitmap = draw {
+            drawText(textLayoutResult)
+        }
+
+        defaultDensity = Density(4f)
+        val bitmap2 = draw {
+            drawText(measurer, longText, style = TextStyle(
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = 20.sp
+            ))
+        }
+
+        assertThat(bitmap).isEqualToBitmap(bitmap2)
+    }
+
+    private fun textMeasurer(
+        fontFamilyResolver: FontFamily.Resolver = this.fontFamilyResolver,
+        density: Density = this.defaultDensity,
+        layoutDirection: LayoutDirection = this.layoutDirection,
+        cacheSize: Int = 0
+    ): TextMeasurer = TextMeasurer(
+        fontFamilyResolver,
+        density,
+        layoutDirection,
+        cacheSize
+    )
+
+    fun draw(
+        width: Float = 1000f,
+        height: Float = 1000f,
+        block: DrawScope.() -> Unit
+    ): Bitmap {
+        val size = Size(width, height)
+        val bitmap = Bitmap.createBitmap(
+            size.width.toIntPx(),
+            size.height.toIntPx(),
+            Bitmap.Config.ARGB_8888
+        )
+        val canvas = Canvas(bitmap.asImageBitmap())
+        val drawScope = CanvasDrawScope()
+        drawScope.draw(
+            defaultDensity,
+            layoutDirection,
+            canvas,
+            size,
+            block
+        )
+        return bitmap
+    }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/SpanStyle.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/SpanStyle.kt
index a886de7..9dcd322 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/SpanStyle.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/SpanStyle.kt
@@ -546,6 +546,23 @@
     }
 
     @OptIn(ExperimentalTextApi::class)
+    internal fun hashCodeLayoutAffectingAttributes(): Int {
+        var result = fontSize.hashCode()
+        result = 31 * result + (fontWeight?.hashCode() ?: 0)
+        result = 31 * result + (fontStyle?.hashCode() ?: 0)
+        result = 31 * result + (fontSynthesis?.hashCode() ?: 0)
+        result = 31 * result + (fontFamily?.hashCode() ?: 0)
+        result = 31 * result + (fontFeatureSettings?.hashCode() ?: 0)
+        result = 31 * result + letterSpacing.hashCode()
+        result = 31 * result + (baselineShift?.hashCode() ?: 0)
+        result = 31 * result + (textGeometricTransform?.hashCode() ?: 0)
+        result = 31 * result + (localeList?.hashCode() ?: 0)
+        result = 31 * result + background.hashCode()
+        result = 31 * result + (platformStyle?.hashCode() ?: 0)
+        return result
+    }
+
+    @OptIn(ExperimentalTextApi::class)
     override fun toString(): String {
         return "SpanStyle(" +
             "color=$color, " +
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurer.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurer.kt
new file mode 100644
index 0000000..e540b13
--- /dev/null
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurer.kt
@@ -0,0 +1,337 @@
+/*
+ * 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.
+ * 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
+
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.Stable
+import androidx.compose.ui.text.caches.LruCache
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.constrain
+import kotlin.math.ceil
+
+/**
+ * Use cases that converge to this number;
+ * - Static text is drawn on canvas for legend and labels.
+ * - Text toggles between enumerated states bold, italic.
+ * - Multiple texts drawn but only their colors are animated.
+ *
+ * If text layout is always called with different inputs, this number is a good stopping point so
+ * that cache does not becomes unnecessarily large and miss penalty stays low. Of course developers
+ * should be aware that in a use case like that the cache should explicitly be disabled.
+ */
+private val DefaultCacheSize = 8
+
+/**
+ * TextMeasurer is responsible for measuring a text in its entirety so that it's ready to be drawn.
+ *
+ * Text layout is a computationally expensive task. Therefore, this class holds an internal LRU
+ * Cache of layout input and output pairs to optimize the repeated measure calls that use the same
+ * input parameters.
+ *
+ * Although most input parameters have a direct influence on layout, some parameters like color,
+ * brush, and shadow can be ignored during layout and set at the end. Using TextMeasurer with
+ * appropriate [cacheSize] should provide significant improvements while animating
+ * non-layout-affecting attributes like color.
+ *
+ * Moreover, if there is a need to render multiple static texts, you can provide the number of texts
+ * by [cacheSize] and their layouts should be cached for repeating calls. Be careful that even a
+ * slight change in input parameters like fontSize, maxLines, an additional character in text would
+ * create a distinct set of input parameters. As a result, a new layout would be calculated and a
+ * new set of input and output pair would be placed in LRU Cache, possibly evicting an earlier
+ * result.
+ *
+ * [FontFamily.Resolver], [LayoutDirection], and [Density] are required parameters to construct a
+ * text layout but they have no safe fallbacks outside of composition. These parameters must be
+ * provided during the construction of a [TextMeasurer] to be used as default values when they
+ * are skipped in [TextMeasurer.measure] call.
+ *
+ * @param fallbackFontFamilyResolver to be used to load fonts given in [TextStyle] and [SpanStyle]s
+ * in [AnnotatedString].
+ * @param fallbackLayoutDirection layout direction of the measurement environment.
+ * @param fallbackDensity density of the measurement environment. Density controls the scaling
+ * factor for fonts.
+ * @param cacheSize Capacity of internal cache inside TextMeasurer. Value of this parameter highly
+ * depends on the consumer use case. Provide a cache size that is in line with how many distinct
+ * text layouts are going to be calculated by this measurer repeatedly. If you are animating font
+ * attributes, or any other layout affecting input, cache can be skipped because most measure calls
+ * would miss the cache.
+ */
+@ExperimentalTextApi
+@Immutable
+class TextMeasurer constructor(
+    private val fallbackFontFamilyResolver: FontFamily.Resolver,
+    private val fallbackDensity: Density,
+    private val fallbackLayoutDirection: LayoutDirection,
+    private val cacheSize: Int = DefaultCacheSize
+) {
+    private val textLayoutCache: TextLayoutCache? = if (cacheSize > 0) {
+        TextLayoutCache(cacheSize)
+    } else null
+
+    /**
+     * Creates a [TextLayoutResult] according to given parameters.
+     *
+     * This function supports laying out text that consists of multiple paragraphs, includes
+     * placeholders, wraps around soft line breaks, and might overflow outside the specified size.
+     *
+     * Most parameters for text affect the final text layout. One pixel change in [size] can
+     * displace a word to another line which would cause a chain reaction that completely changes
+     * how text is rendered. On the other hand, some attributes only play a role when drawing the
+     * created text layout. For example text layout can be created completely in black color but we
+     * can apply [TextStyle.color] later in draw phase. This also means that animating text color
+     * shouldn't invalidate text layout.
+     *
+     * Thus, [textLayoutCache] helps in the process of converting a set of text layout inputs to
+     * a text layout while ignoring non-layout-affecting attributes. Iterative calls that use the
+     * same input parameters should benefit from substantial performance improvements.
+     *
+     * @param text the text to be laid out
+     * @param style the [TextStyle] to be applied to the whole text
+     * @param overflow How visual overflow should be handled.
+     * @param softWrap Whether the text should break at soft line breaks. If false, the glyphs in
+     * the text will be positioned as if there was unlimited horizontal space. If [softWrap] is
+     * false, [overflow] and TextAlign may have unexpected effects.
+     * @param maxLines An optional maximum number of lines for the text to span, wrapping if
+     * necessary. If the text exceeds the given number of lines, it will be truncated according to
+     * [overflow] and [softWrap]. If it is not null, then it must be greater than zero.
+     * @param placeholders a list of [Placeholder]s that specify ranges of text which will be
+     * skipped during layout and replaced with [Placeholder]. It's required that the range of each
+     * [Placeholder] doesn't cross paragraph boundary, otherwise [IllegalArgumentException] is
+     * thrown.
+     * @param size how wide and tall the text is allowed to be. [IntSize.width]
+     * will define the width of the text. [IntSize.height] helps defining the
+     * number of lines that fit if [softWrap] is enabled and [overflow] is [TextOverflow.Ellipsis].
+     * @param layoutDirection layout direction of the measurement environment. If not specified,
+     * defaults to the value that was given during initialization of this [TextMeasurer].
+     * @param density density of the measurement environment. If not specified, defaults to
+     * the value that was given during initialization of this [TextMeasurer].
+     * @param fontFamilyResolver to be used to load the font given in [SpanStyle]s. If not
+     * specified, defaults to the value that was given during initialization of this [TextMeasurer].
+     * @param skipCache Disables cache optimization if it is passed as true.
+     */
+    @Stable
+    fun measure(
+        text: AnnotatedString,
+        style: TextStyle = TextStyle.Default,
+        overflow: TextOverflow = TextOverflow.Clip,
+        softWrap: Boolean = true,
+        maxLines: Int = Int.MAX_VALUE,
+        placeholders: List<AnnotatedString.Range<Placeholder>> = emptyList(),
+        size: IntSize = IntSize(Int.MAX_VALUE, Int.MAX_VALUE),
+        layoutDirection: LayoutDirection = this.fallbackLayoutDirection,
+        density: Density = this.fallbackDensity,
+        fontFamilyResolver: FontFamily.Resolver = this.fallbackFontFamilyResolver,
+        skipCache: Boolean = false
+    ): TextLayoutResult {
+        val constraints = Constraints(maxWidth = size.width, maxHeight = size.height)
+        val requestedTextLayoutInput = TextLayoutInput(
+            text,
+            style,
+            placeholders,
+            maxLines,
+            softWrap,
+            overflow,
+            density,
+            layoutDirection,
+            fontFamilyResolver,
+            constraints
+        )
+
+        val cacheResult = if (!skipCache && textLayoutCache != null) {
+            textLayoutCache.get(requestedTextLayoutInput)
+        } else null
+
+        return if (cacheResult != null) {
+            cacheResult.copy(
+                layoutInput = requestedTextLayoutInput,
+                size = constraints.constrain(
+                    IntSize(
+                        cacheResult.multiParagraph.width.ceilToInt(),
+                        cacheResult.multiParagraph.height.ceilToInt()
+                    )
+                )
+            )
+        } else {
+            layout(requestedTextLayoutInput).also {
+                textLayoutCache?.put(requestedTextLayoutInput, it)
+            }
+        }
+    }
+
+    internal companion object {
+        /**
+         * Computes the visual position of the glyphs for painting the text.
+         *
+         * The text will layout with a width that's as close to its max intrinsic width as possible
+         * while still being greater than or equal to `minWidth` and less than or equal to
+         * `maxWidth`.
+         */
+        private fun layout(
+            textLayoutInput: TextLayoutInput
+        ): TextLayoutResult = with(textLayoutInput) {
+            val nonNullIntrinsics = MultiParagraphIntrinsics(
+                annotatedString = text,
+                style = resolveDefaults(style, layoutDirection),
+                density = density,
+                fontFamilyResolver = fontFamilyResolver,
+                placeholders = placeholders
+            )
+
+            val minWidth = constraints.minWidth
+            val widthMatters = softWrap ||
+                overflow == TextOverflow.Ellipsis
+            val maxWidth = if (widthMatters && constraints.hasBoundedWidth) {
+                constraints.maxWidth
+            } else {
+                Constraints.Infinity
+            }
+
+            // This is a fallback behavior because native text layout doesn't support multiple
+            // ellipsis in one text layout.
+            // When softWrap is turned off and overflow is ellipsis, it's expected that each line
+            // that exceeds maxWidth will be ellipsized.
+            // For example,
+            // input text:
+            //     "AAAA\nAAAA"
+            // maxWidth:
+            //     3 * fontSize that only allow 3 characters to be displayed each line.
+            // expected output:
+            //     AA…
+            //     AA…
+            // Here we assume there won't be any '\n' character when softWrap is false. And make
+            // maxLines 1 to implement the similar behavior.
+            val overwriteMaxLines = !softWrap &&
+                overflow == TextOverflow.Ellipsis
+            val finalMaxLines = if (overwriteMaxLines) 1 else maxLines
+
+            // if minWidth == maxWidth the width is fixed.
+            //    therefore we can pass that value to our paragraph and use it
+            // if minWidth != maxWidth there is a range
+            //    then we should check if the max intrinsic width is in this range to decide the
+            //    width to be passed to Paragraph
+            //        if max intrinsic width is between minWidth and maxWidth
+            //           we can use it to layout
+            //        else if max intrinsic width is greater than maxWidth, we can only use maxWidth
+            //        else if max intrinsic width is less than minWidth, we should use minWidth
+            val width = if (minWidth == maxWidth) {
+                maxWidth
+            } else {
+                nonNullIntrinsics.maxIntrinsicWidth.ceilToInt().coerceIn(minWidth, maxWidth)
+            }
+
+            val multiParagraph = MultiParagraph(
+                intrinsics = nonNullIntrinsics,
+                constraints = Constraints(maxWidth = width, maxHeight = constraints.maxHeight),
+                // This is a fallback behavior for ellipsis. Native
+                maxLines = finalMaxLines,
+                ellipsis = overflow == TextOverflow.Ellipsis
+            )
+
+            return TextLayoutResult(
+                layoutInput = textLayoutInput,
+                multiParagraph = multiParagraph,
+                size = constraints.constrain(
+                    IntSize(
+                        ceil(multiParagraph.width).toInt(),
+                        ceil(multiParagraph.height).toInt()
+                    )
+                )
+            )
+        }
+    }
+}
+
+/**
+ * Keeps an LRU layout cache of TextLayoutInput, TextLayoutResult pairs. Any non-layout affecting
+ * change in TextLayoutInput (color, brush, shadow, TextDecoration) is ignored by this cache.
+ *
+ * @param capacity Maximum initial size of LRU cache.
+ *
+ * @throws IllegalArgumentException if capacity is not a positive integer.
+ */
+internal class TextLayoutCache(capacity: Int = DefaultCacheSize) {
+    private val lruCache = LruCache<CacheTextLayoutInput, TextLayoutResult>(capacity)
+
+    fun get(key: TextLayoutInput): TextLayoutResult? {
+        val resultFromCache = lruCache.get(CacheTextLayoutInput(key)) ?: return null
+
+        if (resultFromCache.multiParagraph.intrinsics.hasStaleResolvedFonts) {
+            // one of the resolved fonts has updated, and this MeasuredText is no longer valid for
+            // measure or display
+            return null
+        }
+
+        return resultFromCache
+    }
+
+    fun put(key: TextLayoutInput, value: TextLayoutResult): TextLayoutResult? {
+        return lruCache.put(CacheTextLayoutInput(key), value)
+    }
+
+    fun remove(key: TextLayoutInput): TextLayoutResult? {
+        return lruCache.remove(CacheTextLayoutInput(key))
+    }
+}
+
+/**
+ * Provides custom hashCode and equals function that are only interested in layout affecting
+ * attributes in TextLayoutInput. Used as a key in [TextLayoutCache].
+ */
+@Immutable
+internal class CacheTextLayoutInput(val textLayoutInput: TextLayoutInput) {
+
+    override fun hashCode(): Int = with(textLayoutInput) {
+        var result = text.hashCode()
+        result = 31 * result + style.hashCodeLayoutAffectingAttributes()
+        result = 31 * result + placeholders.hashCode()
+        result = 31 * result + maxLines
+        result = 31 * result + softWrap.hashCode()
+        result = 31 * result + overflow.hashCode()
+        result = 31 * result + density.hashCode()
+        result = 31 * result + layoutDirection.hashCode()
+        result = 31 * result + fontFamilyResolver.hashCode()
+        result = 31 * result + constraints.maxWidth.hashCode()
+        result = 31 * result + constraints.maxHeight.hashCode()
+        return result
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is CacheTextLayoutInput) return false
+
+        with(textLayoutInput) {
+            if (text != other.textLayoutInput.text) return false
+            if (!style.hasSameLayoutAffectingAttributes(other.textLayoutInput.style)) return false
+            if (placeholders != other.textLayoutInput.placeholders) return false
+            if (maxLines != other.textLayoutInput.maxLines) return false
+            if (softWrap != other.textLayoutInput.softWrap) return false
+            if (overflow != other.textLayoutInput.overflow) return false
+            if (density != other.textLayoutInput.density) return false
+            if (layoutDirection != other.textLayoutInput.layoutDirection) return false
+            if (fontFamilyResolver !== other.textLayoutInput.fontFamilyResolver) return false
+            if (constraints.maxWidth != other.textLayoutInput.constraints.maxWidth) return false
+            if (constraints.maxHeight != other.textLayoutInput.constraints.maxHeight) return false
+        }
+
+        return true
+    }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextPainter.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextPainter.kt
index a97f8cb..2c683d3 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextPainter.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextPainter.kt
@@ -19,10 +19,24 @@
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.geometry.Rect
 import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Canvas
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shadow
+import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.graphics.drawscope.translate
+import androidx.compose.ui.graphics.isUnspecified
+import androidx.compose.ui.graphics.takeOrElse
+import androidx.compose.ui.text.style.TextDecoration
 import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.text.style.modulate
+import androidx.compose.ui.unit.IntSize
+import kotlin.math.ceil
+import kotlin.math.roundToInt
 
 object TextPainter {
+
+    // TODO(b/236964276): Deprecate when TextMeasurer and drawText are no longer Experimental
     /**
      * Paints the text onto the given canvas.
      *
@@ -64,4 +78,253 @@
             }
         }
     }
-}
\ No newline at end of file
+}
+
+/**
+ * Draw styled text using a TextMeasurer.
+ *
+ * This draw function supports multi-styling and async font loading.
+ *
+ * TextMeasurer carries an internal cache to optimize text layout measurement for repeated calls
+ * in draw phase. If layout affecting attributes like font size, font weight, overflow, softWrap,
+ * etc. are changed in consecutive calls to this method, TextMeasurer and its internal cache that
+ * holds layout results may not offer any benefits. Check out [TextMeasurer] and drawText
+ * overloads that take [TextLayoutResult] to learn more about text layout and draw phase
+ * optimizations.
+ *
+ * @param textMeasurer Measures and lays out the text
+ * @param text Text to be drawn
+ * @param topLeft Offsets the text from top left point of the current coordinate system.
+ * @param style the [TextStyle] to be applied to the text
+ * @param overflow How visual overflow should be handled.
+ * @param softWrap Whether the text should break at soft line breaks. If false, the glyphs in
+ * the text will be positioned as if there was unlimited horizontal space. If [softWrap] is
+ * false, [overflow] and TextAlign may have unexpected effects.
+ * @param maxLines An optional maximum number of lines for the text to span, wrapping if
+ * necessary. If the text exceeds the given number of lines, it will be truncated according to
+ * [overflow] and [softWrap]. If it is not null, then it must be greater than zero.
+ * @param placeholders a list of [Placeholder]s that specify ranges of text which will be
+ * skipped during layout and replaced with [Placeholder]. It's required that the range of each
+ * [Placeholder] doesn't cross paragraph boundary, otherwise [IllegalArgumentException] is
+ * thrown.
+ * @param size how wide and tall the text is allowed to be. [IntSize.width] will define the width
+ * of the text. [IntSize.height] helps defining the number of lines that fit if [softWrap] is
+ * enabled and [overflow] is [TextOverflow.Ellipsis]. Otherwise, [IntSize.height] either defines
+ * where the text is clipped ([TextOverflow.Clip]) or becomes no-op.
+ *
+ * @see TextMeasurer
+ */
+@ExperimentalTextApi
+fun DrawScope.drawText(
+    textMeasurer: TextMeasurer,
+    text: AnnotatedString,
+    topLeft: Offset = Offset.Zero,
+    style: TextStyle = TextStyle.Default,
+    overflow: TextOverflow = TextOverflow.Clip,
+    softWrap: Boolean = true,
+    maxLines: Int = Int.MAX_VALUE,
+    placeholders: List<AnnotatedString.Range<Placeholder>> = emptyList(),
+    size: IntSize = IntSize(
+        width = ceil(this.size.width).roundToInt(),
+        height = ceil(this.size.height).roundToInt()
+    )
+) {
+    val textLayoutResult = textMeasurer.measure(
+        text = text,
+        style = style,
+        overflow = overflow,
+        softWrap = softWrap,
+        maxLines = maxLines,
+        placeholders = placeholders,
+        size = size,
+        layoutDirection = layoutDirection,
+        density = this
+    )
+
+    drawText(textLayoutResult, topLeft = topLeft)
+}
+
+/**
+ * Draw text using a TextMeasurer.
+ *
+ * This draw function supports only one text style, and async font loading.
+ *
+ * TextMeasurer carries an internal cache to optimize text layout measurement for repeated calls
+ * in draw phase. If layout affecting attributes like font size, font weight, overflow, softWrap,
+ * etc. are changed in consecutive calls to this method, TextMeasurer and its internal cache that
+ * holds layout results may not offer any benefits. Check out [TextMeasurer] and drawText overloads that take [TextLayoutResult] to learn
+ * more about text layout and draw phase optimizations.
+ *
+ * @param textMeasurer Measures and lays out the text
+ * @param text Text to be drawn
+ * @param topLeft Offsets the text from top left point of the current coordinate system.
+ * @param style the [TextStyle] to be applied to the text
+ * @param overflow How visual overflow should be handled.
+ * @param softWrap Whether the text should break at soft line breaks. If false, the glyphs in
+ * the text will be positioned as if there was unlimited horizontal space. If [softWrap] is
+ * false, [overflow] and TextAlign may have unexpected effects.
+ * @param maxLines An optional maximum number of lines for the text to span, wrapping if
+ * necessary. If the text exceeds the given number of lines, it will be truncated according to
+ * [overflow] and [softWrap]. If it is not null, then it must be greater than zero.
+ * @param size how wide and tall the text is allowed to be. [IntSize.width] will define the width
+ * of the text. [IntSize.height] helps defining the number of lines that fit if [softWrap] is
+ * enabled and [overflow] is [TextOverflow.Ellipsis]. Otherwise, [IntSize.height] either defines
+ * where the text is clipped ([TextOverflow.Clip]) or becomes no-op.
+ *
+ * @see TextMeasurer
+ */
+@ExperimentalTextApi
+fun DrawScope.drawText(
+    textMeasurer: TextMeasurer,
+    text: String,
+    topLeft: Offset = Offset.Zero,
+    style: TextStyle = TextStyle.Default,
+    overflow: TextOverflow = TextOverflow.Clip,
+    softWrap: Boolean = true,
+    maxLines: Int = Int.MAX_VALUE,
+    size: IntSize = IntSize(
+        width = ceil(this.size.width).roundToInt(),
+        height = ceil(this.size.height).roundToInt()
+    )
+) {
+    val textLayoutResult = textMeasurer.measure(
+        text = AnnotatedString(text),
+        style = style,
+        overflow = overflow,
+        softWrap = softWrap,
+        maxLines = maxLines,
+        size = size,
+        layoutDirection = layoutDirection,
+        density = this
+    )
+
+    translate(topLeft.x, topLeft.y) {
+        TextPainter.paint(
+            canvas = this.drawContext.canvas,
+            textLayoutResult = textLayoutResult
+        )
+    }
+}
+
+/**
+ * Draw an existing text layout as produced by [TextMeasurer].
+ *
+ * This draw function cannot relayout when async font loading resolves. If using async fonts or
+ * other dynamic text layout, you are responsible for invalidating layout on changes.
+ *
+ * @param textLayoutResult Text Layout to be drawn
+ * @param color Text color to use
+ * @param topLeft Offsets the text from top left point of the current coordinate system.
+ * @param alpha opacity to be applied to the [color] from 0.0f to 1.0f representing fully
+ * transparent to fully opaque respectively
+ * @param shadow The shadow effect applied on the text.
+ * @param textDecoration The decorations to paint on the text (e.g., an underline).
+ *
+ * @sample androidx.compose.ui.text.samples.DrawTextLayoutResultSample
+ */
+@ExperimentalTextApi
+fun DrawScope.drawText(
+    textLayoutResult: TextLayoutResult,
+    color: Color = Color.Unspecified,
+    topLeft: Offset = Offset.Zero,
+    alpha: Float = Float.NaN,
+    shadow: Shadow? = null,
+    textDecoration: TextDecoration? = null
+) {
+    val newShadow = shadow ?: textLayoutResult.layoutInput.style.shadow
+    val newTextDecoration = textDecoration ?: textLayoutResult.layoutInput.style.textDecoration
+
+    // if text layout was created using brush, and [color] is unspecified, we should treat this
+    // like drawText(brush) call
+    val style = if (textLayoutResult.layoutInput.style.brush != null && color.isUnspecified) {
+        textLayoutResult.layoutInput.style.copy(
+            brush = textLayoutResult.layoutInput.style.brush,
+            alpha = if (!alpha.isNaN()) alpha else textLayoutResult.layoutInput.style.alpha,
+            shadow = newShadow,
+            textDecoration = newTextDecoration
+        )
+    } else {
+        val newColor = color.takeOrElse { textLayoutResult.layoutInput.style.color }.modulate(alpha)
+        textLayoutResult.layoutInput.style.copy(
+            color = newColor,
+            shadow = newShadow,
+            textDecoration = newTextDecoration
+        )
+    }
+
+    translate(topLeft.x, topLeft.y) {
+        TextPainter.paint(
+            canvas = this.drawContext.canvas,
+            textLayoutResult = textLayoutResult.copy(
+                TextLayoutInput(
+                    text = textLayoutResult.layoutInput.text,
+                    style = style,
+                    placeholders = textLayoutResult.layoutInput.placeholders,
+                    maxLines = textLayoutResult.layoutInput.maxLines,
+                    softWrap = textLayoutResult.layoutInput.softWrap,
+                    overflow = textLayoutResult.layoutInput.overflow,
+                    density = textLayoutResult.layoutInput.density,
+                    layoutDirection = textLayoutResult.layoutInput.layoutDirection,
+                    fontFamilyResolver = textLayoutResult.layoutInput.fontFamilyResolver,
+                    constraints = textLayoutResult.layoutInput.constraints,
+                )
+            )
+        )
+    }
+}
+
+/**
+ * Draw an existing text layout as produced by [TextMeasurer].
+ *
+ * This draw function cannot relayout when async font loading resolves. If using async fonts or
+ * other dynamic text layout, you are responsible for invalidating layout on changes.
+ *
+ * @param textLayoutResult Text Layout to be drawn
+ * @param brush The brush to use when drawing the text.
+ * @param topLeft Offsets the text from top left point of the current coordinate system.
+ * @param alpha Opacity to be applied to [brush] from 0.0f to 1.0f representing fully
+ * transparent to fully opaque respectively.
+ * @param shadow The shadow effect applied on the text.
+ * @param textDecoration The decorations to paint on the text (e.g., an underline).
+ *
+ * @sample androidx.compose.ui.text.samples.DrawTextLayoutResultSample
+ */
+@ExperimentalTextApi
+fun DrawScope.drawText(
+    textLayoutResult: TextLayoutResult,
+    brush: Brush,
+    topLeft: Offset = Offset.Zero,
+    alpha: Float = Float.NaN,
+    shadow: Shadow? = null,
+    textDecoration: TextDecoration? = null
+) {
+    val newShadow = shadow ?: textLayoutResult.layoutInput.style.shadow
+    val newTextDecoration = textDecoration ?: textLayoutResult.layoutInput.style.textDecoration
+
+    val style = textLayoutResult.layoutInput.style.copy(
+        brush = brush,
+        alpha = if (!alpha.isNaN()) alpha else textLayoutResult.layoutInput.style.alpha,
+        shadow = newShadow,
+        textDecoration = newTextDecoration
+    )
+
+    translate(topLeft.x, topLeft.y) {
+        TextPainter.paint(
+            canvas = this.drawContext.canvas,
+            textLayoutResult = textLayoutResult.copy(
+                TextLayoutInput(
+                    text = textLayoutResult.layoutInput.text,
+                    style = style,
+                    placeholders = textLayoutResult.layoutInput.placeholders,
+                    maxLines = textLayoutResult.layoutInput.maxLines,
+                    softWrap = textLayoutResult.layoutInput.softWrap,
+                    overflow = textLayoutResult.layoutInput.overflow,
+                    density = textLayoutResult.layoutInput.density,
+                    layoutDirection = textLayoutResult.layoutInput.layoutDirection,
+                    fontFamilyResolver = textLayoutResult.layoutInput.fontFamilyResolver,
+                    constraints = textLayoutResult.layoutInput.constraints,
+                )
+            )
+        )
+    }
+}
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextStyle.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextStyle.kt
index 123266e..11d0b0f 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextStyle.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextStyle.kt
@@ -729,6 +729,14 @@
     }
 
     @OptIn(ExperimentalTextApi::class)
+    internal fun hashCodeLayoutAffectingAttributes(): Int {
+        var result = spanStyle.hashCodeLayoutAffectingAttributes()
+        result = 31 * result + paragraphStyle.hashCode()
+        result = 31 * result + (platformStyle?.hashCode() ?: 0)
+        return result
+    }
+
+    @OptIn(ExperimentalTextApi::class)
     override fun toString(): String {
         return "TextStyle(" +
             "color=$color, " +
diff --git a/compose/ui/ui-util/lint-baseline.xml b/compose/ui/ui-util/lint-baseline.xml
deleted file mode 100644
index 3b664c9..0000000
--- a/compose/ui/ui-util/lint-baseline.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha01" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha01)" variant="all" version="7.4.0-alpha01">
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="inline fun &lt;T> List&lt;T>.fastForEach(action: (T) -> Unit) {"
-        errorLine2="                       ~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/util/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="inline fun &lt;T> List&lt;T>.fastForEachIndexed(action: (Int, T) -> Unit) {"
-        errorLine2="                       ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/util/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="inline fun &lt;T> List&lt;T>.fastAll(predicate: (T) -> Boolean): Boolean {"
-        errorLine2="                       ~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/util/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="inline fun &lt;T> List&lt;T>.fastAny(predicate: (T) -> Boolean): Boolean {"
-        errorLine2="                       ~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/util/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="inline fun &lt;T> List&lt;T>.fastFirstOrNull(predicate: (T) -> Boolean): T? {"
-        errorLine2="                       ~~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/util/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="inline fun &lt;T> List&lt;T>.fastSumBy(selector: (T) -> Int): Int {"
-        errorLine2="                       ~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/util/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="inline fun &lt;T, R> List&lt;T>.fastMap(transform: (T) -> R): List&lt;R> {"
-        errorLine2="                          ~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/util/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="inline fun &lt;T, R : Comparable&lt;R>> List&lt;T>.fastMaxBy(selector: (T) -> R): T? {"
-        errorLine2="                                          ~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/util/ListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="inline fun &lt;T, R, C : MutableCollection&lt;in R>> List&lt;T>.fastMapTo("
-        errorLine2="                                                       ~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/util/ListUtils.kt"/>
-    </issue>
-
-</issues>
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index a5944e3..b4e751a 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -2223,7 +2223,7 @@
     ctor public AbstractComposeView(android.content.Context context, optional android.util.AttributeSet? attrs, optional int defStyleAttr);
     ctor public AbstractComposeView(android.content.Context context, optional android.util.AttributeSet? attrs);
     ctor public AbstractComposeView(android.content.Context context);
-    method @androidx.compose.runtime.Composable public abstract void Content();
+    method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public abstract void Content();
     method public final void createComposition();
     method public final void disposeComposition();
     method public final boolean getHasComposition();
@@ -2978,6 +2978,13 @@
 
 }
 
+package androidx.compose.ui.text {
+
+  public final class TextMeasurerHelperKt {
+  }
+
+}
+
 package androidx.compose.ui.text.input {
 
   public final class CursorAnchorInfoBuilderKt {
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index 0458028..450d6e1 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -2392,7 +2392,7 @@
     ctor public AbstractComposeView(android.content.Context context, optional android.util.AttributeSet? attrs, optional int defStyleAttr);
     ctor public AbstractComposeView(android.content.Context context, optional android.util.AttributeSet? attrs);
     ctor public AbstractComposeView(android.content.Context context);
-    method @androidx.compose.runtime.Composable public abstract void Content();
+    method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public abstract void Content();
     method public final void createComposition();
     method public final void disposeComposition();
     method public final boolean getHasComposition();
@@ -3196,6 +3196,14 @@
 
 }
 
+package androidx.compose.ui.text {
+
+  public final class TextMeasurerHelperKt {
+    method @androidx.compose.runtime.Composable @androidx.compose.ui.text.ExperimentalTextApi public static androidx.compose.ui.text.TextMeasurer rememberTextMeasurer(optional androidx.compose.ui.text.font.FontFamily.Resolver fontFamilyResolver, optional androidx.compose.ui.unit.Density density, optional androidx.compose.ui.unit.LayoutDirection layoutDirection, optional int cacheSize);
+  }
+
+}
+
 package androidx.compose.ui.text.input {
 
   public final class CursorAnchorInfoBuilderKt {
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index ced5b76..89a3ce4 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -2258,7 +2258,7 @@
     ctor public AbstractComposeView(android.content.Context context, optional android.util.AttributeSet? attrs, optional int defStyleAttr);
     ctor public AbstractComposeView(android.content.Context context, optional android.util.AttributeSet? attrs);
     ctor public AbstractComposeView(android.content.Context context);
-    method @androidx.compose.runtime.Composable public abstract void Content();
+    method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public abstract void Content();
     method public final void createComposition();
     method public final void disposeComposition();
     method public final boolean getHasComposition();
@@ -3014,6 +3014,13 @@
 
 }
 
+package androidx.compose.ui.text {
+
+  public final class TextMeasurerHelperKt {
+  }
+
+}
+
 package androidx.compose.ui.text.input {
 
   public final class CursorAnchorInfoBuilderKt {
diff --git a/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposePreciseFingerTapIntegrationBenchmark.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposePreciseFingerTapIntegrationBenchmark.kt
new file mode 100644
index 0000000..2e80a90
--- /dev/null
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposePreciseFingerTapIntegrationBenchmark.kt
@@ -0,0 +1,240 @@
+/*
+ * 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.benchmark.input.pointer
+
+import androidx.compose.foundation.gestures.detectTapGestures
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.requiredHeight
+import androidx.compose.foundation.text.BasicText
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.ComposeTestCase
+import androidx.compose.testutils.benchmark.ComposeBenchmarkRule
+import androidx.compose.testutils.doFramesUntilNoChangesPending
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Benchmark for precise finger tapping (down, move, and up) on an item in Compose created from a
+ * real device.
+ *
+ * The intent is to measure the speed of all parts necessary for a normal finger tap and move
+ * starting from [MotionEvent]s getting dispatched to a particular view.  The test therefore
+ * includes hit testing and dispatch.
+ *
+ * This is intended to be a more through benchmark of [ComposeTapIntegrationBenchmark] and a finger
+ * tapping version of [ComposePreciseStylusTapIntegrationBenchmark].
+ *
+ * The hierarchy is set up to look like:
+ * rootView
+ *   -> Column
+ *     -> Text (with click listener)
+ *     -> Text (with click listener)
+ *     -> Text (with click listener)
+ *     -> ...
+ *
+ * MotionEvents are dispatched to rootView as an ACTION_DOWN, an ACTION_MOVE, and finally
+ * an ACTION_UP.  The validity of the test is verified inside the click listener with
+ * com.google.common.truth.Truth.assertThat and by counting the clicks in the click listener and
+ * later verifying that they count is sufficiently high.
+ */
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class ComposePreciseFingerTapIntegrationBenchmark {
+
+    @get:Rule
+    val benchmarkRule = ComposeBenchmarkRule()
+
+    @Test
+    fun clickOnLateItem() {
+        // As items that are laid out last are hit tested first (so z order is respected), item
+        // at 0 will be hit tested late.
+        clickOnItem(0, "0")
+    }
+
+    // This test requires less hit testing so changes to dispatch will be tracked more by this test.
+    @Test
+    fun clickOnEarlyItemFyi() {
+        // As items that are laid out last are hit tested first (so z order is respected), item
+        // at NumItems - 1 will be hit tested early.
+        val lastItem = NumItems - 1
+        clickOnItem(lastItem, "$lastItem")
+    }
+
+    private fun clickOnItem(item: Int, expectedLabel: String) {
+        val xDown = 0f
+        // half height of an item + top of the chosen item = middle of the chosen item
+        val yDown = (ItemHeightPx / 2) + (item * ItemHeightPx)
+
+        val xMove = xDown + MOVE_AMOUNT_PX
+        val yMove = yDown + MOVE_AMOUNT_PX
+
+        val xUp = xMove + MOVE_AMOUNT_PX
+        val yUp = yMove + MOVE_AMOUNT_PX
+
+        benchmarkRule.runBenchmarkFor({ ComposeTapTestCase() }) {
+            doFramesUntilNoChangesPending()
+
+            val case = getTestCase()
+            case.expectedLabel = expectedLabel
+
+            val rootView = getHostView()
+
+            // Precise Touch/Finger MotionEvents (Down, Move, Up)
+            // Based on real MotionEvents pulled from a device.
+            val fingerDownMotionEvent = android.view.MotionEvent.obtain(
+                8451548L,
+                8451548L,
+                android.view.MotionEvent.ACTION_DOWN,
+                1,
+                arrayOf(
+                    PointerProperties(0).apply {
+                        toolType = android.view.MotionEvent.TOOL_TYPE_FINGER
+                    }
+                ),
+                arrayOf(
+                    PointerCoords(xDown, yDown).apply {
+                        pressure = 1.0f
+                        size = 0.08639053f
+                    }
+                ),
+                0,
+                0,
+                1.000625f,
+                1.0003906f,
+                6,
+                0x0, // Edge Flags value of 0.
+                0x1002, // Source of the event value of 4098
+                0x2 // Motion Event Flags value of 2
+            )
+
+            val fingerMoveMotionEvent = android.view.MotionEvent.obtain(
+                8451548L,
+                8451632L,
+                android.view.MotionEvent.ACTION_MOVE,
+                1,
+                arrayOf(
+                    PointerProperties(0).apply {
+                        toolType = android.view.MotionEvent.TOOL_TYPE_FINGER
+                    }
+                ),
+                arrayOf(
+                    PointerCoords(xMove, yMove).apply {
+                        pressure = 1.0f
+                        size = 0.08639053f
+                    }
+                ),
+                0,
+                0,
+                1.000625f,
+                1.0003906f,
+                6,
+                0x0, // Edge Flags value of 0.
+                0x1002, // Source of the event value of 4098
+                0x2 // Motion Event Flags value of 2
+            )
+
+            val fingerUpMotionEvent = android.view.MotionEvent.obtain(
+                8451548L,
+                8451756L,
+                android.view.MotionEvent.ACTION_UP,
+                1,
+                arrayOf(
+                    PointerProperties(0).apply {
+                        toolType = android.view.MotionEvent.TOOL_TYPE_FINGER
+                    }
+                ),
+                arrayOf(
+                    PointerCoords(xUp, yUp).apply {
+                        pressure = 1.0f
+                        size = 0.08639053f
+                    }
+                ),
+                0,
+                0,
+                1.000625f,
+                1.0003906f,
+                6,
+                0x0, // Edge Flags value of 0.
+                0x1002, // Source of the event value of 4098
+                0x2 // Motion Event Flags value of 2
+            )
+
+            benchmarkRule.measureRepeated {
+
+                rootView.dispatchTouchEvent(fingerDownMotionEvent)
+                rootView.dispatchTouchEvent(fingerMoveMotionEvent)
+                rootView.dispatchTouchEvent(fingerUpMotionEvent)
+
+                case.expectedClickCount++
+                assertThat(case.actualClickCount).isEqualTo(case.expectedClickCount)
+            }
+        }
+    }
+
+    private class ComposeTapTestCase : ComposeTestCase {
+        private var itemHeightDp = 0.dp // Is set to correct value during composition.
+        var actualClickCount = 0
+        var expectedClickCount = 0
+        lateinit var expectedLabel: String
+
+        @Composable
+        override fun Content() {
+            with(LocalDensity.current) {
+                itemHeightDp = ItemHeightPx.toDp()
+            }
+
+            EmailList(NumItems)
+        }
+
+        @Composable
+        fun EmailList(count: Int) {
+            Column {
+                repeat(count) { i ->
+                    Email("$i")
+                }
+            }
+        }
+
+        @Composable
+        fun Email(label: String) {
+            BasicText(
+                text = label,
+                modifier = Modifier
+                    .pointerInput(label) {
+                        detectTapGestures {
+                            assertThat(label).isEqualTo(expectedLabel)
+                            actualClickCount++
+                        }
+                    }
+                    .fillMaxWidth()
+                    .requiredHeight(itemHeightDp)
+            )
+        }
+    }
+    companion object {
+        private const val MOVE_AMOUNT_PX = 30f
+    }
+}
diff --git a/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposePreciseStylusTapIntegrationBenchmark.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposePreciseStylusTapIntegrationBenchmark.kt
new file mode 100644
index 0000000..906d65d
--- /dev/null
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposePreciseStylusTapIntegrationBenchmark.kt
@@ -0,0 +1,253 @@
+/*
+ * 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.benchmark.input.pointer
+
+import androidx.compose.foundation.gestures.awaitFirstDown
+import androidx.compose.foundation.gestures.waitForUpOrCancellation
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.requiredHeight
+import androidx.compose.foundation.text.BasicText
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.ComposeTestCase
+import androidx.compose.testutils.benchmark.ComposeBenchmarkRule
+import androidx.compose.testutils.doFramesUntilNoChangesPending
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.pointer.PointerInputChange
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.isActive
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Benchmark for precise stylus tapping (down, move, and up) on an item in Compose created from a
+ * real device.
+ *
+ * The intent is to measure the speed of all parts necessary for a normal stylus tap and move
+ * starting from [MotionEvent]s getting dispatched to a particular view.  The test therefore
+ * includes hit testing and dispatch.
+ *
+ * This is intended to be a more through benchmark of [ComposeTapIntegrationBenchmark] and a stylus
+ * version of [ComposePreciseFingerTapIntegrationBenchmark].
+ *
+ * The hierarchy is set up to look like:
+ * rootView
+ *   -> Column
+ *     -> Text (with click listener)
+ *     -> Text (with click listener)
+ *     -> Text (with click listener)
+ *     -> ...
+ *
+ * MotionEvents are dispatched to rootView as an ACTION_DOWN, an ACTION_MOVE, and finally
+ * an ACTION_UP.  The validity of the test is verified inside the click listener with
+ * com.google.common.truth.Truth.assertThat and by counting the clicks in the click listener and
+ * later verifying that they count is sufficiently high.
+ */
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class ComposePreciseStylusTapIntegrationBenchmark {
+
+    @get:Rule
+    val benchmarkRule = ComposeBenchmarkRule()
+
+    @Test
+    fun clickOnLateItem() {
+        // As items that are laid out last are hit tested first (so z order is respected), item
+        // at 0 will be hit tested late.
+        clickOnItem(0, "0")
+    }
+
+    // This test requires less hit testing so changes to dispatch will be tracked more by this test.
+    @Test
+    fun clickOnEarlyItemFyi() {
+        // As items that are laid out last are hit tested first (so z order is respected), item
+        // at NumItems - 1 will be hit tested early.
+        val lastItem = NumItems - 1
+        clickOnItem(lastItem, "$lastItem")
+    }
+
+    private fun clickOnItem(item: Int, expectedLabel: String) {
+        val xDown = 0f
+        // half height of an item + top of the chosen item = middle of the chosen item
+        val yDown = (ItemHeightPx / 2) + (item * ItemHeightPx)
+
+        val xMove = xDown + MOVE_AMOUNT_PX
+        val yMove = yDown + MOVE_AMOUNT_PX
+
+        val xUp = xMove + MOVE_AMOUNT_PX
+        val yUp = yMove + MOVE_AMOUNT_PX
+
+        benchmarkRule.runBenchmarkFor({ ComposeTapTestCase() }) {
+            doFramesUntilNoChangesPending()
+
+            val case = getTestCase()
+            case.expectedLabel = expectedLabel
+
+            val rootView = getHostView()
+
+            // Precise Stylus MotionEvents (Down, Move, Up)
+            // Based on real MotionEvents pulled from a device.
+            val stylusDownMotionEvent = android.view.MotionEvent.obtain(
+                346709L,
+                346709L,
+                android.view.MotionEvent.ACTION_DOWN,
+                1,
+                arrayOf(
+                    PointerProperties(0).apply {
+                        toolType = android.view.MotionEvent.TOOL_TYPE_STYLUS
+                    }
+                ),
+                arrayOf(
+                    PointerCoords(xDown, yDown).apply {
+                        pressure = 0.18339439f
+                        size = 0.0f
+                    }
+                ),
+                0,
+                0,
+                1.000625f,
+                1.0003906f,
+                7,
+                0x0, // Edge Flags value of 0.
+                0x5002, // Source of the event value of 20482
+                0x2 // Motion Event Flags value of 2
+            )
+
+            val stylusMoveMotionEvent = android.view.MotionEvent.obtain(
+                346709L,
+                347222L,
+                android.view.MotionEvent.ACTION_MOVE,
+                1,
+                arrayOf(
+                    PointerProperties(0).apply {
+                        toolType = android.view.MotionEvent.TOOL_TYPE_STYLUS
+                    }
+                ),
+                arrayOf(
+                    PointerCoords(xMove, yMove).apply {
+                        pressure = 0.2947497f
+                        size = 0.0f
+                    }
+                ),
+                0,
+                0,
+                1.000625f,
+                1.0003906f,
+                7,
+                0x0, // Edge Flags value of 0.
+                0x5002, // Source of the event value of 20482
+                0x2 // Motion Event Flags value of 2
+            )
+
+            val stylusUpMotionEvent = android.view.MotionEvent.obtain(
+                346709L,
+                347227L,
+                android.view.MotionEvent.ACTION_UP,
+                1,
+                arrayOf(
+                    PointerProperties(0).apply {
+                        toolType = android.view.MotionEvent.TOOL_TYPE_STYLUS
+                    }
+                ),
+                arrayOf(
+                    PointerCoords(xUp, yUp).apply {
+                        pressure = 0.2947497f
+                        size = 0.0f
+                    }
+                ),
+                0,
+                0,
+                1.000625f,
+                1.0003906f,
+                7,
+                0x0, // Edge Flags value of 0.
+                0x5002, // Source of the event value of 20482
+                0x2 // Motion Event Flags value of 2
+            )
+
+            benchmarkRule.measureRepeated {
+
+                rootView.dispatchTouchEvent(stylusDownMotionEvent)
+                rootView.dispatchTouchEvent(stylusMoveMotionEvent)
+                rootView.dispatchTouchEvent(stylusUpMotionEvent)
+
+                case.expectedClickCount++
+                assertThat(case.actualClickCount).isEqualTo(case.expectedClickCount)
+            }
+        }
+    }
+
+    private class ComposeTapTestCase : ComposeTestCase {
+        private var itemHeightDp = 0.dp // Is set to correct value during composition.
+        var actualClickCount = 0
+        var expectedClickCount = 0
+        lateinit var expectedLabel: String
+
+        @Composable
+        override fun Content() {
+            with(LocalDensity.current) {
+                itemHeightDp = ItemHeightPx.toDp()
+            }
+
+            EmailList(NumItems)
+        }
+
+        @Composable
+        fun EmailList(count: Int) {
+            Column {
+                repeat(count) { i ->
+                    Email("$i")
+                }
+            }
+        }
+
+        @Composable
+        fun Email(label: String) {
+            BasicText(
+                text = label,
+                modifier = Modifier
+                    .pointerInput(label) {
+                        coroutineScope {
+                            awaitPointerEventScope {
+                                while (coroutineContext.isActive) {
+                                    val down = awaitFirstDown()
+                                    down.consume()
+
+                                    val upOrCancel: PointerInputChange? = waitForUpOrCancellation()
+                                    upOrCancel?.consume()
+                                    assertThat(label).isEqualTo(expectedLabel)
+                                    actualClickCount++
+                                }
+                            }
+                        }
+                    }
+                    .fillMaxWidth()
+                    .requiredHeight(itemHeightDp)
+            )
+        }
+    }
+    companion object {
+        private const val MOVE_AMOUNT_PX = 30f
+    }
+}
diff --git a/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposeTapIntegrationBenchmark.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposeTapIntegrationBenchmark.kt
index f8cf39f..3ce42b3 100644
--- a/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposeTapIntegrationBenchmark.kt
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposeTapIntegrationBenchmark.kt
@@ -93,6 +93,7 @@
 
             val rootView = getHostView()
 
+            // Simple Events
             val down = MotionEvent(
                 0,
                 android.view.MotionEvent.ACTION_DOWN,
diff --git a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/focus/CustomFocusOrderDemo.kt b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/focus/CustomFocusOrderDemo.kt
index 512c599..7c9c0d6 100644
--- a/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/focus/CustomFocusOrderDemo.kt
+++ b/compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/focus/CustomFocusOrderDemo.kt
@@ -24,6 +24,7 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.requiredWidth
+import androidx.compose.material.Switch
 import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
@@ -34,6 +35,7 @@
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.FocusRequester.Companion.Default
 import androidx.compose.ui.focus.focusProperties
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.focus.focusTarget
@@ -51,64 +53,60 @@
     Column {
         Row {
             Text(
-                "Use the arrow keys to move focus left/right/up/down " +
-                    "and the tab and shift+tab key to move next/previous"
+                "Use the arrow keys to move focus left/right/up/down."
             )
         }
         Column(Modifier.fillMaxSize(), SpaceEvenly) {
             val (item1, item2, item3, item4) = remember { FocusRequester.createRefs() }
-            Row(Modifier.fillMaxWidth(), SpaceEvenly) {
-                FocusableText(
-                    text = "1",
-                    modifier = Modifier
-                        .focusRequester(item1)
-                        .focusProperties {
-                            next = item2
-                            right = item2
-                            down = item3
-                            previous = item4
-                        }
-                )
-                FocusableText(
-                    text = "2",
-                    modifier = Modifier
-                        .focusRequester(item2)
-                        .focusProperties {
-                            next = item3
-                            left = item1
-                            down = item4
-                            previous = item1
-                        }
-                )
+            var wrapAround by remember { mutableStateOf(false) }
+            Row {
+                Text("Wrap around focus search")
+                Switch(checked = wrapAround, onCheckedChange = { wrapAround = !wrapAround })
             }
             Row(Modifier.fillMaxWidth(), SpaceEvenly) {
-                FocusableText(
-                    text = "3",
-                    modifier = Modifier
-                        .focusRequester(item3)
-                        .focusProperties {
-                            next = item4
-                            right = item4
-                            up = item1
-                            previous = item2
-                        }
-                )
-                FocusableText(
-                    text = "4",
-                    modifier = Modifier
-                        .focusRequester(item4)
-                        .focusProperties {
-                            next = item1
-                            left = item3
-                            up = item2
-                            previous = item3
-                        }
-                )
-            }
-            DisposableEffect(Unit) {
-                item1.requestFocus()
-                onDispose { }
-            }
+                    FocusableText(
+                        text = "1",
+                        modifier = Modifier
+                            .focusRequester(item1)
+                            .focusProperties {
+                                left = if (wrapAround) item2 else Default
+                                up = if (wrapAround) item3 else Default
+                            }
+                    )
+                        FocusableText(
+                        text = "2",
+                        modifier = Modifier
+                            .focusRequester(item2)
+                            .focusProperties {
+                                right = if (wrapAround) item1 else Default
+                                up = if (wrapAround) item4 else Default
+                            }
+                    )
+                }
+                Row(Modifier.fillMaxWidth(), SpaceEvenly) {
+                    FocusableText(
+                        text = "3",
+                        modifier = Modifier
+                            .focusRequester(item3)
+                            .focusProperties {
+                                left = if (wrapAround) item4 else Default
+                                down = if (wrapAround) item1 else Default
+                            }
+                    )
+                    FocusableText(
+                        text = "4",
+                        modifier = Modifier
+                            .focusRequester(item4)
+                            .focusProperties {
+                                right = if (wrapAround) item3 else Default
+                                down = if (wrapAround) item2 else Default
+                            }
+                    )
+                }
+                DisposableEffect(Unit) {
+                    item1.requestFocus()
+                    onDispose { }
+                }
         }
     }
 }
diff --git a/compose/ui/ui/lint-baseline.xml b/compose/ui/ui/lint-baseline.xml
deleted file mode 100644
index 086592c..0000000
--- a/compose/ui/ui/lint-baseline.xml
+++ /dev/null
@@ -1,220 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha01" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha01)" variant="all" version="7.4.0-alpha01">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 26 (current min is 21): `waitAndScreenShot`"
-        errorLine1="        val bitmap = rule.waitAndScreenShot()"
-        errorLine2="                          ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/draw/AlphaTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 29 (current min is 21): `RenderNodeApi29`"
-        errorLine1="        RenderNodeApi29(AndroidComposeView(activity)).apply {"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 29 (current min is 21): `setCameraDistance`"
-        errorLine1="            this.cameraDistance = cameraDistance"
-        errorLine2="                 ~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 29 (current min is 21): `dumpRenderNodeData`"
-        errorLine1="        }.dumpRenderNodeData().cameraDistance == cameraDistance"
-        errorLine2="          ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 23 (current min is 21): `RenderNodeApi23`"
-        errorLine1="        RenderNodeApi23(AndroidComposeView(activity)).apply {"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 23 (current min is 21): `setCameraDistance`"
-        errorLine1="            this.cameraDistance = cameraDistance"
-        errorLine2="                 ~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 23 (current min is 21): `dumpRenderNodeData`"
-        errorLine1="        }.dumpRenderNodeData().cameraDistance == -cameraDistance // Camera distance is negative"
-        errorLine2="          ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 26 (current min is 21): `waitAndScreenShot`"
-        errorLine1="    val bitmap = waitAndScreenShot()"
-        errorLine2="                 ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 26 (current min is 21): `waitAndScreenShot`"
-        errorLine1="        val bitmap = rule.waitAndScreenShot()"
-        errorLine2="                          ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/draw/ClipDrawTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 26 (current min is 21): `captureToImage`"
-        errorLine1="    fun SemanticsNodeInteraction.captureToBitmap() = captureToImage().asAndroidBitmap()"
-        errorLine2="                                                     ~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 26 (current min is 21): `captureToImage`"
-        errorLine1="            .captureToImage()"
-        errorLine2="             ~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/draw/InvalidatingNotPlacedChildTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 26 (current min is 21): `waitAndScreenShot`"
-        errorLine1="        val bitmap = rule.waitAndScreenShot()"
-        errorLine2="                          ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/draw/ShadowTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 26 (current min is 21): `captureToImage`"
-        errorLine1="        val bitmap = rule.onRoot().captureToImage().asAndroidBitmap()"
-        errorLine2="                                   ~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/VectorTest.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, R> List&lt;T>.fastZipWithNext(transform: (T, T) -> R): List&lt;R> {"
-        errorLine2="                                   ~~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;S, T : S> List&lt;T>.fastReduce(operation: (acc: S, T) -> S): S {"
-        errorLine2="                                       ~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, K, V> List&lt;T>.fastAssociate(transform: (T) -> Pair&lt;K, V>): Map&lt;K, V> {"
-        errorLine2="                                      ~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, R, V> List&lt;T>.fastZip("
-        errorLine2="                                      ~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="BanInlineOptIn"
-        message="Inline functions cannot opt into experimental APIs."
-        errorLine1="internal inline fun &lt;T, R> List&lt;T>.fastMapNotNull(transform: (T) -> R?): List&lt;R> {"
-        errorLine2="                                   ~~~~~~~~~~~~~~">
-        <location
-            file="src/commonMain/kotlin/androidx/compose/ui/TempListUtils.kt"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    fun testNoopBlur() {"
-        errorLine2="        ~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/draw/BlurTest.kt"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    fun testRectBoundedBlur() {"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/draw/BlurTest.kt"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    fun testUnboundedBlur() {"
-        errorLine2="        ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/draw/BlurTest.kt"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    fun testCircleBoundedBlur() {"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/draw/BlurTest.kt"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    fun testRectangleBlurredEdgeTreatmentHasShape() {"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/draw/BlurTest.kt"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    fun testUnboundedBlurredEdgeTreatmentDoesNotHaveShape() {"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidAndroidTest/kotlin/androidx/compose/ui/draw/BlurTest.kt"/>
-    </issue>
-
-</issues>
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalTest.kt
index 68e5d6a..e519805 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/TwoDimensionalFocusTraversalTest.kt
@@ -30,6 +30,7 @@
 import androidx.compose.ui.platform.LocalFocusManager
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
@@ -61,6 +62,7 @@
         fun initParameters() = listOf(Param(Left), Param(Right), Param(Up), Param(Down))
     }
 
+    @FlakyTest(bugId = 233373546)
     @OptIn(ExperimentalComposeUiApi::class)
     @Test
     fun movesFocusAmongSiblingsDeepInTheFocusHierarchy() {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt
index 780227e..2d5bf83 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/nestedscroll/NestedScrollModifierTest.kt
@@ -17,22 +17,46 @@
 package androidx.compose.ui.input.nestedscroll
 
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.text.BasicText
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.background
 import androidx.compose.ui.draw.clipToBounds
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.platform.AbstractComposeView
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.unit.Velocity
 import androidx.compose.ui.unit.dp
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.CoordinatesProvider
+import androidx.test.espresso.action.GeneralLocation
+import androidx.test.espresso.action.GeneralSwipeAction
+import androidx.test.espresso.action.Press
+import androidx.test.espresso.action.Swipe
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import kotlin.math.abs
+import kotlin.math.sign
 import kotlinx.coroutines.isActive
 import kotlinx.coroutines.runBlocking
+import org.hamcrest.CoreMatchers.allOf
+import org.hamcrest.CoreMatchers.instanceOf
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -961,7 +985,133 @@
         }
     }
 
-    // helper functions
+    @Test
+    fun nestedScroll_movingTarget_velocityShouldRespectSign() {
+        var lastVelocity = Velocity.Zero
+        val MaxOffsetBound = 900f
+        val ConsumedEverything = 0.0f
+        rule.setContent {
+            var offset by remember {
+                mutableStateOf(MaxOffsetBound)
+            }
+            val nestedScrollConnection = remember {
+                object : NestedScrollConnection {
+                    fun consumedDelta(scrollDelta: Float): Float {
+                        if (offset == 0f && scrollDelta < 0f) return ConsumedEverything
+                        if (offset == MaxOffsetBound && scrollDelta > 0f) return ConsumedEverything
+                        val previousOffset = offset
+                        offset = (scrollDelta + offset).coerceIn(0f, MaxOffsetBound)
+                        return offset - previousOffset
+                    }
+
+                    override fun onPreScroll(
+                        available: Offset,
+                        source: NestedScrollSource
+                    ): Offset {
+                        return if (available.y < 0) {
+                            val consumed = consumedDelta(available.y)
+                            Offset(x = 0f, y = consumed)
+                        } else Offset.Zero
+                    }
+
+                    override fun onPostScroll(
+                        consumed: Offset,
+                        available: Offset,
+                        source: NestedScrollSource
+                    ): Offset {
+                        return if (abs(available.y) > 0f &&
+                            available.y > 0f
+                        ) {
+                            Offset(0f, consumedDelta(available.y))
+                        } else
+                            super.onPostScroll(consumed, available, source)
+                    }
+
+                    override suspend fun onPreFling(available: Velocity): Velocity {
+                        lastVelocity = available
+                        return super.onPreFling(available)
+                    }
+                }
+            }
+
+            Column(modifier = Modifier.fillMaxSize()) {
+                Box(
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .height(80.dp)
+                )
+                LazyColumn(
+                    modifier = Modifier
+                        .graphicsLayer {
+                            translationY = offset
+                        }
+                        .nestedScroll(connection = nestedScrollConnection)
+                        .fillMaxWidth()
+                        .weight(1f)
+                ) {
+                    items(100) {
+                        Box(
+                            modifier = Modifier
+                                .fillMaxWidth()
+                                .height(60.dp)
+                                .background(Color.Gray)
+                        ) {
+                            BasicText(text = it.toString())
+                        }
+                        Spacer(modifier = Modifier.height(8.dp))
+                    }
+                }
+            }
+        }
+
+        composeViewSwipeUp()
+        rule.runOnIdle {
+            // swipe ups provide negative signed velocities
+            assertThat(sign(lastVelocity.y)).isEqualTo(-1)
+        }
+        composeViewSwipeDown()
+        rule.runOnIdle {
+            // swipe downs provide positive signed velocities
+            assertThat(sign(lastVelocity.y)).isEqualTo(1)
+        }
+        composeViewSwipeDown()
+        rule.runOnIdle {
+            // swipe downs provide positive signed velocities
+            assertThat(sign(lastVelocity.y)).isEqualTo(1)
+        }
+    }
+
+// helper functions
+
+    private fun composeViewSwipeUp() {
+        onView(allOf(instanceOf(AbstractComposeView::class.java)))
+            .perform(
+                espressoSwipe(
+                    GeneralLocation.BOTTOM_CENTER,
+                    GeneralLocation.CENTER
+                )
+            )
+    }
+
+    private fun composeViewSwipeDown() {
+        onView(allOf(instanceOf(AbstractComposeView::class.java)))
+            .perform(
+                espressoSwipe(
+                    GeneralLocation.CENTER,
+                    GeneralLocation.BOTTOM_CENTER
+                )
+            )
+    }
+
+    private fun espressoSwipe(
+        start: CoordinatesProvider,
+        end: CoordinatesProvider
+    ): GeneralSwipeAction {
+        return GeneralSwipeAction(
+            Swipe.FAST, start, end,
+            Press.FINGER
+        )
+    }
 
     private fun testMiddleParentAdditionRemoval(
         content: @Composable (root: Modifier, middle: Modifier, child: Modifier) -> Unit
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextMeasurerHelperTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextMeasurerHelperTest.kt
new file mode 100644
index 0000000..ff12cf1
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/text/TextMeasurerHelperTest.kt
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalTextApi::class)
+
+package androidx.compose.ui.text
+
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalFontFamilyResolver
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.text.font.createFontFamilyResolver
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TextMeasurerHelperTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    val context = InstrumentationRegistry.getInstrumentation().targetContext
+
+    @Test
+    fun whenFontFamilyResolverChanges_TextMeasurerShouldChange() {
+        val fontFamilyResolver = mutableStateOf(createFontFamilyResolver(context))
+        val measurers = mutableSetOf<TextMeasurer>()
+
+        rule.setContent {
+            CompositionLocalProvider(
+                LocalFontFamilyResolver provides fontFamilyResolver.value
+            ) {
+                val textMeasurer = rememberTextMeasurer()
+                measurers.add(textMeasurer)
+            }
+        }
+
+        rule.waitForIdle()
+        // FontFamily.Resolver implementation has only instance check for equality
+        // new instance should always be unequal to any other instance
+        fontFamilyResolver.value = createFontFamilyResolver(context)
+        rule.waitForIdle()
+
+        assertThat(measurers.size).isEqualTo(2)
+    }
+
+    @Test
+    fun whenDensityChanges_TextMeasurerShouldChange() {
+        val density = mutableStateOf(Density(1f))
+        val measurers = mutableSetOf<TextMeasurer>()
+
+        rule.setContent {
+            CompositionLocalProvider(
+                LocalDensity provides density.value
+            ) {
+                val textMeasurer = rememberTextMeasurer()
+                measurers.add(textMeasurer)
+            }
+        }
+
+        rule.waitForIdle()
+        density.value = Density(2f)
+        rule.waitForIdle()
+
+        assertThat(measurers.size).isEqualTo(2)
+    }
+
+    @Test
+    fun whenLayoutDirectionChanges_TextMeasurerShouldChange() {
+        val layoutDirection = mutableStateOf(LayoutDirection.Ltr)
+        val measurers = mutableSetOf<TextMeasurer>()
+
+        rule.setContent {
+            CompositionLocalProvider(
+                LocalLayoutDirection provides layoutDirection.value
+            ) {
+                val textMeasurer = rememberTextMeasurer()
+                measurers.add(textMeasurer)
+            }
+        }
+
+        rule.waitForIdle()
+        layoutDirection.value = LayoutDirection.Rtl
+        rule.waitForIdle()
+
+        assertThat(measurers.size).isEqualTo(2)
+    }
+
+    @Test
+    fun whenCacheSizeChanges_TextMeasurerShouldChange() {
+        val cacheSize = mutableStateOf(4)
+        val measurers = mutableSetOf<TextMeasurer>()
+
+        rule.setContent {
+            val textMeasurer = rememberTextMeasurer(cacheSize = cacheSize.value)
+            measurers.add(textMeasurer)
+        }
+
+        rule.waitForIdle()
+        cacheSize.value = 8
+        rule.waitForIdle()
+
+        assertThat(measurers.size).isEqualTo(2)
+    }
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt
index 4787b78..0ccde49 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/ComposeView.android.kt
@@ -27,6 +27,7 @@
 import androidx.compose.runtime.Recomposer
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.ui.InternalComposeUiApi
+import androidx.compose.ui.UiComposable
 import androidx.compose.ui.node.InternalCoreApi
 import androidx.compose.ui.node.Owner
 import androidx.lifecycle.Lifecycle
@@ -170,6 +171,7 @@
      * whichever comes first.
      */
     @Composable
+    @UiComposable
     abstract fun Content()
 
     /**
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/util/VelocityTracker.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/util/VelocityTracker.kt
index 869c0e6..dc8372e 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/util/VelocityTracker.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/pointer/util/VelocityTracker.kt
@@ -19,6 +19,7 @@
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.pointer.PointerInputChange
+import androidx.compose.ui.input.pointer.changedToDownIgnoreConsumed
 import androidx.compose.ui.unit.Velocity
 import androidx.compose.ui.util.fastForEach
 import kotlin.math.abs
@@ -26,6 +27,7 @@
 
 private const val AssumePointerMoveStoppedMilliseconds: Int = 40
 private const val HistorySize: Int = 20
+
 // TODO(b/204895043): Keep value in sync with VelocityPathFinder.HorizonMilliSeconds
 private const val HorizonMilliseconds: Int = 100
 private const val MinSampleSize: Int = 3
@@ -47,6 +49,7 @@
     // Circular buffer; current sample at index.
     private val samples: Array<PointAtTime?> = Array(HistorySize) { null }
     private var index: Int = 0
+    internal var currentPointerPositionAccumulator = Offset.Zero
 
     /**
      * Adds a position as the given time to the tracker.
@@ -167,14 +170,48 @@
  * For optimal tracking, this should be called for the DOWN event and all MOVE
  * events, including any touch-slop-captured MOVE event.
  *
+ * Since Compose uses relative positions inside PointerInputChange, this should be
+ * taken into consideration when using this method. Right now, we use the first down
+ * to initialize an accumulator and use subsequent deltas to simulate an actual movement
+ * from relative positions in PointerInputChange. This is required because VelocityTracker
+ * requires data that can be fit into a curve, which might not happen with relative positions
+ * inside a moving target for instance.
+ *
  * @param event Pointer change to track.
  */
 fun VelocityTracker.addPointerInputChange(event: PointerInputChange) {
+
+    // Register down event as the starting point for the accumulator
+    if (event.changedToDownIgnoreConsumed()) {
+        currentPointerPositionAccumulator = event.position
+        resetTracking()
+    }
+
+    // To calculate delta, for each step we want to  do currentPosition - previousPosition.
+    // Initially the previous position is the previous position of the current event
+    var previousPointerPosition = event.previousPosition
     @OptIn(ExperimentalComposeUiApi::class)
     event.historical.fastForEach {
-        addPosition(it.uptimeMillis, it.position)
+        // Historical data happens within event.position and event.previousPosition
+        // That means, event.previousPosition < historical data < event.position
+        // Initially, the first delta will happen between the previousPosition and
+        // the first position in historical delta. For subsequent historical data, the
+        // deltas happen between themselves. That's why we need to update previousPointerPosition
+        // everytime.
+        val historicalDelta = it.position - previousPointerPosition
+        previousPointerPosition = it.position
+
+        // Update the current position with the historical delta and add it to the tracker
+        currentPointerPositionAccumulator += historicalDelta
+        addPosition(it.uptimeMillis, currentPointerPositionAccumulator)
     }
-    addPosition(event.uptimeMillis, event.position)
+
+    // For the last position in the event
+    // If there's historical data, the delta is event.position - lastHistoricalPoint
+    // If there's no historical data, the delta is event.position - event.previousPosition
+    val delta = event.position - previousPointerPosition
+    currentPointerPositionAccumulator += delta
+    addPosition(event.uptimeMillis, currentPointerPositionAccumulator)
 }
 
 private data class PointAtTime(val point: Offset, val time: Long)
@@ -182,7 +219,7 @@
 /**
  * A two dimensional velocity estimate.
  *
- * VelocityEstimates are computed by [VelocityTracker.getVelocityEstimate]. An
+ * VelocityEstimates are computed by [VelocityTracker.getImpulseVelocity]. An
  * estimate's [confidence] measures how well the velocity tracker's position
  * data fit a straight line, [durationMillis] is the time that elapsed between the
  * first and last position sample used to compute the velocity, and [offset]
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurerHelper.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurerHelper.kt
new file mode 100644
index 0000000..b745d89
--- /dev/null
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/text/TextMeasurerHelper.kt
@@ -0,0 +1,59 @@
+/*
+ * 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
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalFontFamilyResolver
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+
+/**
+ * This value should reflect the default cache size for TextMeasurer.
+ */
+private val DefaultCacheSize: Int = 8
+
+/**
+ * Creates and remembers a [TextMeasurer] that reads default values for optional parameters from
+ * CompositionLocals. Returned TextMeasurer also carries an internal [TextLayoutCache] at a given
+ * capacity. Provide 0 as capacity to opt-out from internal caching behavior.
+ *
+ * All given parameters can be overridden during a [TextMeasurer.measure] call except the maximum
+ * size of the TextLayoutCache. Instead the cache can be disabled at will during measure by passing
+ * in skipCache as true.
+ *
+ * @param fontFamilyResolver default [FontFamily.Resolver] to be used to load the font given
+ * in [SpanStyle]s.
+ * @param density default density.
+ * @param layoutDirection default layout direction.
+ * @param cacheSize Capacity of internal cache inside TextMeasurer.
+ */
+@ExperimentalTextApi
+@Composable
+fun rememberTextMeasurer(
+    fontFamilyResolver: FontFamily.Resolver = LocalFontFamilyResolver.current,
+    density: Density = LocalDensity.current,
+    layoutDirection: LayoutDirection = LocalLayoutDirection.current,
+    cacheSize: Int = DefaultCacheSize
+): TextMeasurer {
+    return remember(fontFamilyResolver, density, layoutDirection, cacheSize) {
+        TextMeasurer(fontFamilyResolver, density, layoutDirection, cacheSize)
+    }
+}
\ No newline at end of file
diff --git a/concurrent/concurrent-futures/lint-baseline.xml b/concurrent/concurrent-futures/lint-baseline.xml
index e0c0f6d..4a0dcb5 100644
--- a/concurrent/concurrent-futures/lint-baseline.xml
+++ b/concurrent/concurrent-futures/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="BanSynchronizedMethods"
@@ -7,16 +7,9 @@
         errorLine1="                            @Override"
         errorLine2="                            ^">
         <location
-            file="src/main/java/androidx/concurrent/futures/AbstractResolvableFuture.java"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="        @Override"
-        errorLine2="        ^">
-        <location
-            file="src/main/java/androidx/concurrent/futures/CallbackToFutureAdapter.java"/>
+            file="src/main/java/androidx/concurrent/futures/AbstractResolvableFuture.java"
+            line="224"
+            column="29"/>
     </issue>
 
     <issue
@@ -25,7 +18,9 @@
         errorLine1="    public final void addListener(Runnable listener, Executor executor) {"
         errorLine2="                                  ~~~~~~~~">
         <location
-            file="src/main/java/androidx/concurrent/futures/AbstractResolvableFuture.java"/>
+            file="src/main/java/androidx/concurrent/futures/AbstractResolvableFuture.java"
+            line="652"
+            column="35"/>
     </issue>
 
     <issue
@@ -34,7 +29,9 @@
         errorLine1="    public final void addListener(Runnable listener, Executor executor) {"
         errorLine2="                                                     ~~~~~~~~">
         <location
-            file="src/main/java/androidx/concurrent/futures/AbstractResolvableFuture.java"/>
+            file="src/main/java/androidx/concurrent/futures/AbstractResolvableFuture.java"
+            line="652"
+            column="54"/>
     </issue>
 
     <issue
@@ -43,7 +40,9 @@
         errorLine1="    protected boolean setException(Throwable throwable) {"
         errorLine2="                                   ~~~~~~~~~">
         <location
-            file="src/main/java/androidx/concurrent/futures/AbstractResolvableFuture.java"/>
+            file="src/main/java/androidx/concurrent/futures/AbstractResolvableFuture.java"
+            line="709"
+            column="36"/>
     </issue>
 
     <issue
@@ -52,34 +51,9 @@
         errorLine1="    protected boolean setFuture(ListenableFuture&lt;? extends V> future) {"
         errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="src/main/java/androidx/concurrent/futures/AbstractResolvableFuture.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static &lt;V> ResolvableFuture&lt;V> create() {"
-        errorLine2="                      ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/concurrent/futures/ResolvableFuture.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public boolean setException(Throwable throwable) {"
-        errorLine2="                                ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/concurrent/futures/ResolvableFuture.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public boolean setFuture(ListenableFuture&lt;? extends V> future) {"
-        errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/concurrent/futures/ResolvableFuture.java"/>
+            file="src/main/java/androidx/concurrent/futures/AbstractResolvableFuture.java"
+            line="745"
+            column="33"/>
     </issue>
 
 </issues>
diff --git a/contentpager/contentpager/lint-baseline.xml b/contentpager/contentpager/lint-baseline.xml
index afaf7df..2454363 100644
--- a/contentpager/contentpager/lint-baseline.xml
+++ b/contentpager/contentpager/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/core/core-animation/lint-baseline.xml b/core/core-animation/lint-baseline.xml
index c6237fb..7ae08c1 100644
--- a/core/core-animation/lint-baseline.xml
+++ b/core/core-animation/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="ResourceType"
diff --git a/core/core-appdigest/lint-baseline.xml b/core/core-appdigest/lint-baseline.xml
index 8e14e7e..e141bfd 100644
--- a/core/core-appdigest/lint-baseline.xml
+++ b/core/core-appdigest/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/core/core-google-shortcuts/lint-baseline.xml b/core/core-google-shortcuts/lint-baseline.xml
index 960ad5d..69e10c9 100644
--- a/core/core-google-shortcuts/lint-baseline.xml
+++ b/core/core-google-shortcuts/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/core/core-i18n/src/androidTest/java/androidx/core/i18n/MessageFormatDateTimeTest.java b/core/core-i18n/src/androidTest/java/androidx/core/i18n/MessageFormatDateTimeTest.java
new file mode 100644
index 0000000..00ecfc0
--- /dev/null
+++ b/core/core-i18n/src/androidTest/java/androidx/core/i18n/MessageFormatDateTimeTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.core.i18n;
+
+import android.content.Context;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+@RunWith(AndroidJUnit4.class)
+public class MessageFormatDateTimeTest {
+    private Context mAppContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+    private Calendar mTestCalendar = new GregorianCalendar(
+            2022, Calendar.SEPTEMBER, 27, // Date
+            21, 42, 12 // Time
+    );
+    private Date mTestDate = mTestCalendar.getTime();
+    private long mTestMillis = mTestCalendar.getTimeInMillis();
+
+    @Test @SmallTest
+    public void testSimpleStyles() { // date formatting using JDK styles
+        String expected = "Your card expires on Tuesday, September 27, 2022.";
+        String message = "Your card expires on {exp, date, FULL}.";
+
+        Assert.assertEquals(expected,
+                MessageFormat.formatNamedArgs(mAppContext, message, "exp", mTestDate));
+        Assert.assertEquals(expected,
+                MessageFormat.formatNamedArgs(mAppContext, message, "exp", mTestMillis));
+        Assert.assertEquals(expected,
+                MessageFormat.formatNamedArgs(mAppContext, message, "exp", mTestCalendar));
+    }
+
+    @Test @SmallTest
+    public void testSimpleSkeleton() { // date formatting using date-time skeletons
+        String expected = "Your card expires on Tue, Sep 27, 2022.";
+        String message = "Your card expires on {exp, date, ::yMMMdE}.";
+
+        Assert.assertEquals(expected,
+                MessageFormat.formatNamedArgs(mAppContext, message, "exp", mTestDate));
+        Assert.assertEquals(expected,
+                MessageFormat.formatNamedArgs(mAppContext, message, "exp", mTestMillis));
+        Assert.assertEquals(expected,
+                MessageFormat.formatNamedArgs(mAppContext, message, "exp", mTestCalendar));
+    }
+
+    @Test @SmallTest
+    public void testSimplePattern() { // date formatting using date-time patterns. Bad i18n.
+        String expected = "Your card expires on Tuesday, 27 of September, 2022.";
+        String message = "Your card expires on {exp, date,EEEE, d 'of' MMMM, y}.";
+
+        Assert.assertEquals(expected,
+                MessageFormat.formatNamedArgs(mAppContext, message, "exp", mTestDate));
+        Assert.assertEquals(expected,
+                MessageFormat.formatNamedArgs(mAppContext, message, "exp", mTestMillis));
+
+        // This does not work, see testAndroidCannotFormatCalendar() below.
+        try {
+            Assert.assertEquals(expected,
+                    MessageFormat.formatNamedArgs(mAppContext, message, "exp", mTestCalendar));
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    /*
+     * Showing that the Android classes in java.text can't format Calendar objects.
+     * For now we do the same (we throw the same exception).
+     * TBD if worth the trouble to implement a workaround, since the skeletons and
+     * Java date/time styles work (because our compat classes).
+     * And using patterns is a bad i18n practice, so we don't want to encourage it / make it easy.
+     */
+    @Test @SmallTest
+    public void testAndroidCannotFormatCalendar() {
+        try {
+            DateFormat.getDateInstance(DateFormat.LONG).format(mTestCalendar);
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            new SimpleDateFormat("MMMM d, y").format(mTestCalendar);
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            java.text.MessageFormat.format("The date is {0,date,LONG}", mTestCalendar);
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            java.text.MessageFormat.format("The date is {0,date,MMMM d, y}", mTestCalendar);
+        } catch (IllegalArgumentException e) {
+        }
+    }
+}
diff --git a/core/core-i18n/src/main/java/androidx/core/i18n/MessageFormat.kt b/core/core-i18n/src/main/java/androidx/core/i18n/MessageFormat.kt
index eeb7a61..cb33e84 100644
--- a/core/core-i18n/src/main/java/androidx/core/i18n/MessageFormat.kt
+++ b/core/core-i18n/src/main/java/androidx/core/i18n/MessageFormat.kt
@@ -33,12 +33,12 @@
          */
         @JvmStatic @JvmOverloads
         fun formatNamedArgs(
-            @Suppress("UNUSED_PARAMETER") context: Context,
+            context: Context,
             locale: Locale = Locale.getDefault(),
             msg: String,
             vararg nameValuePairs: Any?
         ): String {
-            return MessageFormat.formatNamedArgs(locale, msg, *nameValuePairs)
+            return MessageFormat.formatNamedArgs(context, locale, msg, *nameValuePairs)
         }
 
         /**
diff --git a/core/core-i18n/src/main/java/androidx/core/i18n/messageformat_icu/simple/DateTimeFormatterAsFormat.kt b/core/core-i18n/src/main/java/androidx/core/i18n/messageformat_icu/simple/DateTimeFormatterAsFormat.kt
new file mode 100644
index 0000000..55e7d9a
--- /dev/null
+++ b/core/core-i18n/src/main/java/androidx/core/i18n/messageformat_icu/simple/DateTimeFormatterAsFormat.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.core.i18n.messageformat_icu.simple
+
+import androidx.core.i18n.DateTimeFormatter
+import java.text.DateFormat
+import java.text.FieldPosition
+import java.text.Format
+import java.text.ParseException
+import java.text.ParsePosition
+import java.util.Calendar
+import java.util.Date
+import java.util.Objects
+
+/**
+ * Decorator for [DateTimeFormatter], because [MessageFormat] expects formatters that
+ * extend [java.text.Format].
+ */
+internal class DateTimeFormatterAsFormat(private val realFormatter: DateTimeFormatter) : Format() {
+    override fun format(
+        obj: Any,
+        stringBuffer: StringBuffer,
+        fieldPosition: FieldPosition
+    ): StringBuffer {
+        val result = when (obj) {
+            is Date -> realFormatter.format(obj)
+            is Calendar -> realFormatter.format(obj)
+            is Long -> realFormatter.format(obj)
+            else -> Objects.toString(obj)
+        }
+        return stringBuffer.append(result)
+    }
+
+    override fun parseObject(s: String, parsePosition: ParsePosition): Any {
+        java.text.SimpleDateFormat.getDateInstance(DateFormat.LONG).parseObject("")
+        throw ParseException("Parsing not implemented", 0)
+    }
+}
\ No newline at end of file
diff --git a/core/core-i18n/src/main/java/androidx/core/i18n/messageformat_icu/simple/MessageFormat.java b/core/core-i18n/src/main/java/androidx/core/i18n/messageformat_icu/simple/MessageFormat.java
index dbc7e73..ed3de9a 100644
--- a/core/core-i18n/src/main/java/androidx/core/i18n/messageformat_icu/simple/MessageFormat.java
+++ b/core/core-i18n/src/main/java/androidx/core/i18n/messageformat_icu/simple/MessageFormat.java
@@ -10,6 +10,8 @@
  */
 package androidx.core.i18n.messageformat_icu.simple;
 
+import android.content.Context;
+
 import java.io.IOException;
 import java.io.InvalidObjectException;
 import java.text.AttributedCharacterIterator;
@@ -36,6 +38,9 @@
 import java.util.Set;
 
 import androidx.annotation.RestrictTo;
+import androidx.core.i18n.DateTimeFormatter;
+import androidx.core.i18n.DateTimeFormatterJdkStyleOptions;
+import androidx.core.i18n.DateTimeFormatterSkeletonOptions;
 import androidx.core.i18n.messageformat_icu.impl.PatternProps;
 import androidx.core.i18n.messageformat_icu.simple.PluralRules.PluralType;
 import androidx.core.i18n.messageformat_icu.text.MessagePattern;
@@ -98,7 +103,7 @@
  * A numbered pattern argument is matched with a map key that contains that number
  * as an ASCII-decimal-digit string (without leading zero).
  *
- * <h4><a name="patterns">Patterns and Their Interpretation</a></h4>
+ * <h3><a name="patterns">Patterns and Their Interpretation</a></h3>
  *
  * <code>MessageFormat</code> uses patterns of the following form:
  * <blockquote><pre>
@@ -122,14 +127,16 @@
  * argNumber = '0' | ('1'..'9' ('0'..'9')*)
  *
  * argType = "number" | "date" | "time" | "spellout" | "ordinal" | "duration"
- * argStyle = "short" | "medium" | "long" | "full" | "integer" | "currency" | "percent" | argStyleText
+ * argStyle = "short" | "medium" | "long" | "full" | "integer" | "currency" | "percent" | argStyleText | "::" argSkeletonText
  * </pre></blockquote>
  *
  * <ul>
+ *   <li>{@code ::argSkeletonText} is only supported for {@code date} and {@code time},
+ *       not {@code number}</li>
  *   <li>messageText can contain quoted literal strings including syntax characters.
  *       A quoted literal string begins with an ASCII apostrophe and a syntax character
  *       (usually a {curly brace}) and continues until the next single apostrophe.
- *       A double ASCII apostrohpe inside or outside of a quoted string represents
+ *       A double ASCII apostrophe inside or outside of a quoted string represents
  *       one literal apostrophe.
  *   <li>Quotable syntax characters are the {curly braces} in all messageText parts,
  *       plus the '#' sign in a messageText immediately inside a pluralStyle,
@@ -139,8 +146,8 @@
  *       and unquoted {curly braces} must occur in matched pairs.
  * </ul>
  *
- * <p>Recommendation: Use the real apostrophe (single quote) character \u2019 for
- * human-readable text, and use the ASCII apostrophe (\u0027 ' )
+ * <p>Recommendation: Use the real apostrophe (single quote) character \\u2019 for
+ * human-readable text, and use the ASCII apostrophe (\\u0027 ' )
  * only in program syntax, like quoting in MessageFormat.
  * See the annotations for U+0027 Apostrophe in The Unicode Standard.
  *
@@ -154,7 +161,7 @@
  * shown in the table are illegal. Any <code>argStyleText</code> must
  * be a valid pattern string for the Format subclass used.
  *
- * <p><table border=1>
+ * <table border=1>
  *    <tr>
  *       <th>argType
  *       <th>argStyle
@@ -179,7 +186,7 @@
  *       <td><i>argStyleText</i>
  *       <td><code>new DecimalFormat(argStyleText, new DecimalFormatSymbols(getLocale()))</code>
  *    <tr>
- *       <td rowspan=6><code>date</code>
+ *       <td rowspan=7><code>date</code>
  *       <td><i>(none)</i>
  *       <td><code>DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale())</code>
  *    <tr>
@@ -196,7 +203,10 @@
  *       <td><code>DateFormat.getDateInstance(DateFormat.FULL, getLocale())</code>
  *    <tr>
  *       <td><i>argStyleText</i>
- *       <td><code>new SimpleDateFormat(argStyleText, getLocale())
+ *       <td><code>new SimpleDateFormat(argStyleText, getLocale())</code>
+ *    <tr>
+ *       <td><i>argSkeletonText</i>
+ *       <td><code>DateFormat.getInstanceForSkeleton(argSkeletonText, getLocale())</code>
  *    <tr>
  *       <td rowspan=6><code>time</code>
  *       <td><i>(none)</i>
@@ -215,24 +225,23 @@
  *       <td><code>DateFormat.getTimeInstance(DateFormat.FULL, getLocale())</code>
  *    <tr>
  *       <td><i>argStyleText</i>
- *       <td><code>new SimpleDateFormat(argStyleText, getLocale())
+ *       <td><code>new SimpleDateFormat(argStyleText, getLocale())</code>
  *    <tr>
  *       <td><code>spellout</code>
  *       <td><i>argStyleText (optional)</i>
  *       <td><code>new RuleBasedNumberFormat(getLocale(), RuleBasedNumberFormat.SPELLOUT)
- *           <br/>&nbsp;&nbsp;&nbsp;&nbsp;.setDefaultRuleset(argStyleText);</code>
+ *           <br>&nbsp;&nbsp;&nbsp;&nbsp;.setDefaultRuleset(argStyleText);</code>
  *    <tr>
  *       <td><code>ordinal</code>
  *       <td><i>argStyleText (optional)</i>
  *       <td><code>new RuleBasedNumberFormat(getLocale(), RuleBasedNumberFormat.ORDINAL)
- *           <br/>&nbsp;&nbsp;&nbsp;&nbsp;.setDefaultRuleset(argStyleText);</code>
+ *           <br>&nbsp;&nbsp;&nbsp;&nbsp;.setDefaultRuleset(argStyleText);</code>
  *    <tr>
  *       <td><code>duration</code>
  *       <td><i>argStyleText (optional)</i>
  *       <td><code>new RuleBasedNumberFormat(getLocale(), RuleBasedNumberFormat.DURATION)
- *           <br/>&nbsp;&nbsp;&nbsp;&nbsp;.setDefaultRuleset(argStyleText);</code>
+ *           <br>&nbsp;&nbsp;&nbsp;&nbsp;.setDefaultRuleset(argStyleText);</code>
  * </table>
- * <p>
  *
  * <h4><a name="diffsjdk">Differences from java.text.MessageFormat</a></h4>
  *
@@ -253,6 +262,28 @@
  * The JDK MessageFormat does create and use a ChoiceFormat object
  * (<code>new ChoiceFormat(argStyleText)</code>).
  * The JDK does not support plural and select arguments at all.
+
+ * <p>Both the ICU and the JDK <code>MessageFormat</code> can control the argument
+ * formats by using <code>argStyle</code>. But the JDK <code>MessageFormat</code> only
+ * supports predefined formats and number / date / time pattern strings (which would need
+ * to be localized).<br>
+ * ICU supports everything the JDK does, and also number / date / time <b>skeletons</b> using the
+ * <code>::</code> prefix (which automatically yield output appropriate for the
+ * <code>MessageFormat</code> locale).</p>
+ *
+ * <h4>Argument formatting</h4>
+ *
+ * <p>Arguments are formatted according to their type, using the default
+ * ICU formatters for those types, unless otherwise specified.
+ * For unknown types, <code>MessageFormat</code> will call <code>toString()</code>.</p>
+ *
+ * <p>There are also several ways to control the formatting.</p>
+ *
+ * <p>We recommend you use default styles, predefined style values, skeletons,
+ * or preformatted values, but not pattern strings or custom format objects.</p>
+ *
+ * <p>For more details, see the
+ * <a href="https://unicode-org.github.io/icu/userguide/format_parse/messages">ICU User Guide</a>.</p>
  *
  * <h4>Usage Information</h4>
  *
@@ -266,10 +297,10 @@
  * };
  *
  * String result = MessageFormat.format(
- *     "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
+ *     "At {1,time,::jmm} on {1,date,::dMMMM}, there was {2} on planet {0,number,integer}.",
  *     arguments);
  *
- * <em>output</em>: At 12:30 PM on Jul 3, 2053, there was a disturbance
+ * <em>output</em>: At 4:34 PM on March 23, there was a disturbance
  *           in the Force on planet 7.
  *
  * </pre>
@@ -308,7 +339,7 @@
  * System.out.println(msgFmt.format(args));
  * args.put("num_files", 3);
  * System.out.println(msgFmt.format(args));
- * 
+ *
  * <em>output</em>:
  * There are no files on disk "MyDisk".
  * There are 3 files on "MyDisk".
@@ -349,9 +380,10 @@
      * @param msg an ICU-MessageFormat-syntax string
      * @param nameValuePairs (argument name, argument value) pairs
      */
-    public static final String formatNamedArgs(Locale locale, String msg, Object... nameValuePairs) {
+    public static final String formatNamedArgs(Context context, Locale locale,
+                                               String msg, Object... nameValuePairs) {
         StringBuilder result = new StringBuilder(msg.length());
-        new MessageFormat(msg, locale).format(0, null, null, null, nameValuePairs,
+        new MessageFormat(context, msg, locale).format(0, null, null, null, nameValuePairs,
                 new AppendableWrapper(result), null);
         return result.toString();
     }
@@ -366,8 +398,9 @@
      * @see Category#FORMAT
      * icu_annot::stable ICU 3.0
      */
-    public MessageFormat(String pattern) {
+    public MessageFormat(Context context, String pattern) {
         locale_ = Locale.getDefault();  // Category.FORMAT
+        context_ = context;
         applyPattern(pattern);
     }
 
@@ -381,8 +414,9 @@
      * @exception IllegalArgumentException if the pattern is invalid
      * icu_annot::stable ICU 3.0
      */
-    public MessageFormat(String pattern, Locale locale) {
+    public MessageFormat(Context context, String pattern, Locale locale) {
         locale_ = locale;
+        context_ = context;
         applyPattern(pattern);
     }
 
@@ -446,7 +480,7 @@
     }
 
     /**
-     * {icu_annot::icu} 
+     * {icu_annot::icu}
      * @return this instance's ApostropheMode.
      * icu_annot::stable ICU 4.8
      */
@@ -748,7 +782,7 @@
                     "This method is not available in MessageFormat objects " +
                     "that use alphanumeric argument names.");
         }
-        ArrayList<Format> list = new ArrayList<Format>();
+        ArrayList<Format> list = new ArrayList<>();
         for (int partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
             int argNumber = msgPattern.getPart(partIndex + 1).getValue();
             while (argNumber >= list.size()) {
@@ -781,7 +815,7 @@
      * icu_annot::stable ICU 3.0
      */
     public Format[] getFormats() {
-        ArrayList<Format> list = new ArrayList<Format>();
+        ArrayList<Format> list = new ArrayList<>();
         for (int partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
             list.add(cachedFormatters == null ? null : cachedFormatters.get(partIndex));
         }
@@ -795,7 +829,7 @@
      * icu_annot::stable ICU 4.8
      */
     public Set<String> getArgumentNames() {
-        Set<String> result = new HashSet<String>();
+        Set<String> result = new HashSet<>();
         for (int partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
             result.add(getArgName(partIndex + 1));
         }
@@ -837,7 +871,7 @@
      * argument is <i>unavailable</i> if <code>arguments</code> is
      * <code>null</code> or has fewer than argumentIndex+1 elements.  When
      * an argument is unavailable no substitution is performed.
-     * <p>
+     *
      * <table border=1>
      *    <tr>
      *       <th>argType or Format
@@ -909,7 +943,7 @@
      * <p>
      * The text substituted for the individual format elements is derived from
      * the current subformat of the format element and the
-     * <code>arguments</code> value corresopnding to the format element's
+     * <code>arguments</code> value corresponding to the format element's
      * argument name.
      * <p>
      * A numbered pattern argument is matched with a map key that contains that number
@@ -952,8 +986,8 @@
      * @throws IllegalArgumentException if this format uses named arguments
      * icu_annot::stable ICU 3.0
      */
-    public static String format(String pattern, Object... arguments) {
-        MessageFormat temp = new MessageFormat(pattern);
+    public static String format(Context context, String pattern, Object... arguments) {
+        MessageFormat temp = new MessageFormat(context, pattern);
         return temp.format(arguments);
     }
 
@@ -970,8 +1004,8 @@
      * @see #format(String, Object[])
      * icu_annot::stable ICU 3.8
      */
-    public static String format(String pattern, Map<String, Object> arguments) {
-        MessageFormat temp = new MessageFormat(pattern);
+    public static String format(Context context, String pattern, Map<String, Object> arguments) {
+        MessageFormat temp = new MessageFormat(context, pattern);
         return temp.format(arguments);
     }
 
@@ -1007,7 +1041,7 @@
      * @throws IllegalArgumentException if an argument in
      *         <code>arguments</code> is not of the type
      *         expected by the format element(s) that use it
-     * @throws IllegalArgumentException if <code>arguments<code> is
+     * @throws IllegalArgumentException if <code>arguments</code> is
      *         an array of Object and this format uses named arguments
      * icu_annot::stable ICU 3.0
      */
@@ -1108,7 +1142,7 @@
                     "This method is not available in MessageFormat objects " +
                     "that use named argument.");
         }
-        
+
         // Count how many slots we need in the array.
         int maxArgId = -1;
         for (int partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
@@ -1127,7 +1161,7 @@
 
         return resultArray;
     }
-    
+
     /**
      * {icu_annot::icu} Parses the string, returning the results in a Map.
      * This is similar to the version that returns an array
@@ -1142,15 +1176,15 @@
      * icu_annot::stable ICU 3.8
      */
     public Map<String, Object> parseToMap(String source, ParsePosition pos)  {
-        Map<String, Object> result = new HashMap<String, Object>();
+        Map<String, Object> result = new HashMap<>();
         int backupStartPos = pos.getIndex();
         parse(0, source, pos, null, result);
         if (pos.getIndex() == backupStartPos) {
             return null;
         }
-        return result;        
+        return result;
     }
-    
+
     /**
      * Parses text from the beginning of the given string to produce an object
      * array.
@@ -1226,7 +1260,7 @@
             // We do not support parsing Plural formats. (No REPLACE_NUMBER here.)
             assert type==Part.Type.ARG_START : "Unexpected Part "+part+" in parsed message.";
             int argLimit=msgPattern.getLimitPartIndex(i);
-            
+
             ArgType argType=part.getArgType();
             part=msgPattern.getPart(++i);
             // Compute the argId, so we can use it as a key.
@@ -1330,7 +1364,7 @@
      */
     public Map<String, Object> parseToMap(String source) throws ParseException {
         ParsePosition pos = new ParsePosition(0);
-        Map<String, Object> result = new HashMap<String, Object>();
+        Map<String, Object> result = new HashMap<>();
         parse(0, source, pos, null, result);
         if (pos.getIndex() == 0) // unchanged, returned object is null
             throw new ParseException("MessageFormat parse error!",
@@ -1385,10 +1419,10 @@
         if (obj == null || getClass() != obj.getClass())
             return false;
         MessageFormat other = (MessageFormat) obj;
-        return Utility.objectEquals(ulocale, other.ulocale)
-                && Utility.objectEquals(msgPattern, other.msgPattern)
-                && Utility.objectEquals(cachedFormatters, other.cachedFormatters)
-                && Utility.objectEquals(customFormatArgStarts, other.customFormatArgStarts);
+        return Objects.equals(ulocale, other.ulocale)
+                && Objects.equals(msgPattern, other.msgPattern)
+                && Objects.equals(cachedFormatters, other.cachedFormatters)
+                && Objects.equals(customFormatArgStarts, other.customFormatArgStarts);
         // Note: It might suffice to only compare custom formatters
         // rather than all formatters.
     }
@@ -1470,6 +1504,11 @@
     private transient Locale locale_;
 
     /**
+     * The Android Context to used to access user preferences and other Android functionality.
+     */
+    private transient Context context_;
+
+    /**
      * The MessagePattern which contains the parsed structure of the pattern string.
      */
     private transient MessagePattern msgPattern;
@@ -1745,7 +1784,7 @@
      * as soon as it finds an argument, or it reaches the end of the string.
      * @param from Index in the pattern string to start from.
      * @return A substring from the pattern string representing the longest possible
-     *         substring with no arguments. 
+     *         substring with no arguments.
      */
     private String getLiteralStringUntilNextArgument(int from) {
         StringBuilder b = new StringBuilder();
@@ -2102,6 +2141,19 @@
         DATE_MODIFIER_LONG = 3,
         DATE_MODIFIER_FULL = 4;
 
+    Format dateTimeFormatForPatternOrSkeleton(String style) {
+        // Ignore leading whitespace when looking for "::", the skeleton signal sequence
+        int i = PatternProps.skipWhiteSpace(style, 0);
+        if (style.regionMatches(i, "::", 0, 2)) { // Skeleton
+            DateTimeFormatter df = new DateTimeFormatter(context_,
+                DateTimeFormatterSkeletonOptions.fromString(style.substring(i + 2)),
+                locale_);
+            return new DateTimeFormatterAsFormat(df);
+        } else { // Pattern
+            return new SimpleDateFormat(style, locale_);
+        }
+    }
+
     // Creates an appropriate Format object for the type and style passed.
     // Both arguments cannot be null.
     private Format createAppropriateFormat(String type, String style) {
@@ -2131,44 +2183,74 @@
         case TYPE_DATE:
             switch (findKeyword(style, dateModifierList)) {
             case DATE_MODIFIER_EMPTY:
-                newFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, locale_);
+                newFormat = new DateTimeFormatterAsFormat(
+                    new DateTimeFormatter(
+                            DateTimeFormatterJdkStyleOptions.createDateInstance(DateFormat.DEFAULT),
+                                locale_));
                 break;
             case DATE_MODIFIER_SHORT:
-                newFormat = DateFormat.getDateInstance(DateFormat.SHORT, locale_);
+                newFormat = new DateTimeFormatterAsFormat(
+                    new DateTimeFormatter(
+                        DateTimeFormatterJdkStyleOptions.createDateInstance(DateFormat.SHORT),
+                        locale_));
                 break;
             case DATE_MODIFIER_MEDIUM:
-                newFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, locale_);
+                newFormat = new DateTimeFormatterAsFormat(
+                    new DateTimeFormatter(
+                        DateTimeFormatterJdkStyleOptions.createDateInstance(DateFormat.DEFAULT),
+                        locale_));
                 break;
             case DATE_MODIFIER_LONG:
-                newFormat = DateFormat.getDateInstance(DateFormat.LONG, locale_);
+                newFormat = new DateTimeFormatterAsFormat(
+                    new DateTimeFormatter(
+                        DateTimeFormatterJdkStyleOptions.createDateInstance(DateFormat.LONG),
+                        locale_));
                 break;
             case DATE_MODIFIER_FULL:
-                newFormat = DateFormat.getDateInstance(DateFormat.FULL, locale_);
+                newFormat = new DateTimeFormatterAsFormat(
+                    new DateTimeFormatter(
+                        DateTimeFormatterJdkStyleOptions.createDateInstance(DateFormat.FULL),
+                        locale_));
                 break;
-            default:
-                newFormat = new SimpleDateFormat(style, locale_);
+            default: // pattern or skeleton
+                newFormat = dateTimeFormatForPatternOrSkeleton(style);
                 break;
             }
             break;
         case TYPE_TIME:
             switch (findKeyword(style, dateModifierList)) {
             case DATE_MODIFIER_EMPTY:
-                newFormat = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale_);
+                newFormat = new DateTimeFormatterAsFormat(
+                    new DateTimeFormatter(
+                        DateTimeFormatterJdkStyleOptions.createTimeInstance(DateFormat.DEFAULT),
+                        locale_));
                 break;
             case DATE_MODIFIER_SHORT:
-                newFormat = DateFormat.getTimeInstance(DateFormat.SHORT, locale_);
+                newFormat = new DateTimeFormatterAsFormat(
+                    new DateTimeFormatter(
+                        DateTimeFormatterJdkStyleOptions.createTimeInstance(DateFormat.SHORT),
+                        locale_));
                 break;
             case DATE_MODIFIER_MEDIUM:
-                newFormat = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale_);
+                newFormat = new DateTimeFormatterAsFormat(
+                    new DateTimeFormatter(
+                        DateTimeFormatterJdkStyleOptions.createTimeInstance(DateFormat.DEFAULT),
+                        locale_));
                 break;
             case DATE_MODIFIER_LONG:
-                newFormat = DateFormat.getTimeInstance(DateFormat.LONG, locale_);
+                newFormat = new DateTimeFormatterAsFormat(
+                    new DateTimeFormatter(
+                        DateTimeFormatterJdkStyleOptions.createTimeInstance(DateFormat.LONG),
+                        locale_));
                 break;
             case DATE_MODIFIER_FULL:
-                newFormat = DateFormat.getTimeInstance(DateFormat.FULL, locale_);
+                newFormat = new DateTimeFormatterAsFormat(
+                    new DateTimeFormatter(
+                        DateTimeFormatterJdkStyleOptions.createTimeInstance(DateFormat.FULL),
+                        locale_));
                 break;
-            default:
-                newFormat = new SimpleDateFormat(style, locale_);
+            default: // pattern or skeleton
+                newFormat = dateTimeFormatForPatternOrSkeleton(style);
                 break;
             }
             break;
@@ -2276,7 +2358,7 @@
      */
     private void setArgStartFormat(int argStart, Format formatter) {
         if (cachedFormatters == null) {
-            cachedFormatters = new HashMap<Integer, Format>();
+            cachedFormatters = new HashMap<>();
         }
         cachedFormatters.put(argStart, formatter);
     }
@@ -2288,7 +2370,7 @@
     private void setCustomArgStartFormat(int argStart, Format formatter) {
         setArgStartFormat(argStart, formatter);
         if (customFormatArgStarts == null) {
-            customFormatArgStarts = new HashSet<Integer>();
+            customFormatArgStarts = new HashSet<>();
         }
         customFormatArgStarts.add(argStart);
     }
@@ -2306,12 +2388,12 @@
      * {icu_annot::icu} Converts an 'apostrophe-friendly' pattern into a standard
      * pattern.
      * <em>This is obsolete for ICU 4.8 and higher MessageFormat pattern strings.</em>
-     * It can still be useful together with the JDK MessageFormat.
+     * It can still be useful together with {@link java.text.MessageFormat}.
      *
      * <p>See the class description for more about apostrophes and quoting,
-     * and differences between ICU and the JDK.
+     * and differences between ICU and {@link java.text.MessageFormat}.
      *
-     * <p>The JDK MessageFormat and ICU 4.6 and earlier MessageFormat
+     * <p>{@link java.text.MessageFormat} and ICU 4.6 and earlier MessageFormat
      * treat all ASCII apostrophes as
      * quotes, which is problematic in some languages, e.g.
      * French, where apostrophe is commonly used.  This utility
@@ -2415,7 +2497,7 @@
         }
 
         public void useAttributes() {
-            attributes = new ArrayList<AttributeAndPosition>();
+            attributes = new ArrayList<>();
         }
 
         public void append(CharSequence s) {
diff --git a/core/core-ktx/lint-baseline.xml b/core/core-ktx/lint-baseline.xml
index 4463aae..6364b8a 100644
--- a/core/core-ktx/lint-baseline.xml
+++ b/core/core-ktx/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index c02cb38..bb46e53 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -1388,7 +1388,7 @@
     method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
     method public static void setTint(android.graphics.drawable.Drawable, @ColorInt int);
     method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList?);
-    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode);
+    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode?);
     method public static <T extends android.graphics.drawable.Drawable> T! unwrap(android.graphics.drawable.Drawable);
     method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
   }
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt
index 191403e..f6099ee 100644
--- a/core/core/api/public_plus_experimental_current.txt
+++ b/core/core/api/public_plus_experimental_current.txt
@@ -1388,7 +1388,7 @@
     method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
     method public static void setTint(android.graphics.drawable.Drawable, @ColorInt int);
     method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList?);
-    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode);
+    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode?);
     method public static <T extends android.graphics.drawable.Drawable> T! unwrap(android.graphics.drawable.Drawable);
     method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
   }
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 3a6cb54..615169b 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -1660,7 +1660,7 @@
     method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
     method public static void setTint(android.graphics.drawable.Drawable, @ColorInt int);
     method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList?);
-    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode);
+    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode?);
     method public static <T extends android.graphics.drawable.Drawable> T! unwrap(android.graphics.drawable.Drawable);
     method public static android.graphics.drawable.Drawable wrap(android.graphics.drawable.Drawable);
   }
diff --git a/core/core/src/androidTest/AndroidManifest.xml b/core/core/src/androidTest/AndroidManifest.xml
index acd1fb7..d87622f 100644
--- a/core/core/src/androidTest/AndroidManifest.xml
+++ b/core/core/src/androidTest/AndroidManifest.xml
@@ -106,6 +106,10 @@
             android:name="androidx.core.widget.EdgeEffectCompatTest$EdgeEffectCompatTestActivity"
             android:exported="true" />
         <activity
+            android:name="androidx.core.app.ComponentActivity"
+            android:exported="true" />
+
+        <activity
             android:name="androidx.core.view.WindowCompatActivity"
             android:exported="true"
             android:theme="@android:style/Theme.Light.NoTitleBar" />
diff --git a/core/core/src/androidTest/java/androidx/core/widget/NestedScrollViewStretchFlingTest.kt b/core/core/src/androidTest/java/androidx/core/widget/NestedScrollViewStretchFlingTest.kt
new file mode 100644
index 0000000..90dd90e
--- /dev/null
+++ b/core/core/src/androidTest/java/androidx/core/widget/NestedScrollViewStretchFlingTest.kt
@@ -0,0 +1,183 @@
+/*
+ * 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.core.widget
+
+import android.animation.ValueAnimator
+import android.graphics.Color
+import android.os.Build
+import android.view.MotionEvent
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import androidx.core.app.ComponentActivity
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.testutils.PollingCheck
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+/**
+ * On S and higher, a large fling back should remove the stretch and start flinging the content.
+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
+@MediumTest
+class NestedScrollViewStretchFlingTest {
+    lateinit var nestedScrollView: NestedScrollView
+
+    @Rule
+    @JvmField
+    @Suppress("DEPRECATION")
+    val mRule = ActivityScenarioRule(ComponentActivity::class.java)
+
+    @Before
+    fun setup() {
+        val drawLatch = CountDownLatch(1)
+        mRule.scenario.onActivity { activity ->
+            nestedScrollView = NestedScrollView(activity)
+            val layoutParams = ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT
+            )
+            activity.setContentView(nestedScrollView, layoutParams)
+
+            val linearLayout = LinearLayout(activity)
+            linearLayout.orientation = LinearLayout.VERTICAL
+            val linearLayoutParams = ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT
+            )
+            nestedScrollView.addView(linearLayout, linearLayoutParams)
+
+            repeat(1000) {
+                val child = FrameLayout(activity)
+                child.setBackgroundColor(Color.HSVToColor(floatArrayOf(it * 10f, 1f, 1f)))
+                val childLayoutParams = ViewGroup.LayoutParams(50, 50)
+                linearLayout.addView(child, childLayoutParams)
+            }
+            nestedScrollView.viewTreeObserver.addOnPreDrawListener {
+                drawLatch.countDown()
+                true
+            }
+
+            // Disabled animations will cause EdgeEffects to not do anything.
+            // This will enable animations for our Activity.
+            val setDurationScale =
+                ValueAnimator::class.java.getDeclaredMethod("setDurationScale", Float::class.java)
+
+            setDurationScale.invoke(null, 1f)
+        }
+        assertTrue(drawLatch.await(1, TimeUnit.SECONDS))
+    }
+
+    @Test
+    fun flingContentAfterStretchOnTop() {
+        stretchThenFling(stretchMotionUp = false) {
+            assertTrue(nestedScrollView.mEdgeGlowTop.distance > 0f)
+            assertEquals(0, nestedScrollView.scrollY)
+        }
+
+        // Wait for the stretch to release
+        PollingCheck.waitFor(1000L) {
+            nestedScrollView.mEdgeGlowTop.isFinished
+        }
+
+        var lastScroll = 0
+        PollingCheck.waitFor(1000L) {
+            var nextScroll = 0
+            mRule.scenario.onActivity {
+                nextScroll = nestedScrollView.scrollY
+            }
+            val changed = nextScroll == lastScroll
+            lastScroll = nextScroll
+            !changed
+        }
+
+        assertTrue(lastScroll > 0)
+    }
+
+    @Test
+    fun flingContentAfterStretchOnBottom() {
+        mRule.scenario.onActivity {
+            nestedScrollView.scrollTo(0, nestedScrollView.scrollRange)
+            assertEquals(nestedScrollView.scrollRange, nestedScrollView.scrollY)
+        }
+        stretchThenFling(stretchMotionUp = true) {
+            assertTrue(nestedScrollView.mEdgeGlowBottom.distance > 0f)
+            assertEquals(nestedScrollView.scrollRange, nestedScrollView.scrollY)
+        }
+
+        // Wait for the stretch to release
+        PollingCheck.waitFor(1000L) {
+            nestedScrollView.mEdgeGlowBottom.isFinished
+        }
+
+        var lastScroll = 0
+        PollingCheck.waitFor(1000L) {
+            var nextScroll = 0
+            mRule.scenario.onActivity {
+                nextScroll = nestedScrollView.scrollY
+            }
+            val changed = nextScroll == lastScroll
+            lastScroll = nextScroll
+            !changed
+        }
+
+        assertTrue(lastScroll < nestedScrollView.scrollRange)
+    }
+
+    private fun stretchThenFling(stretchMotionUp: Boolean, onFlingStart: () -> Unit) {
+        val x = nestedScrollView.width / 2f
+        val yStart = nestedScrollView.height / 2f
+
+        val yStretch = if (stretchMotionUp) 0f else nestedScrollView.height.toFloat()
+
+        val stretchTime = 20L
+        val endStretchTime = 500L
+
+        val events = mutableListOf<MotionEvent>()
+        // down
+        events += MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, x, yStart, 0)
+        // stretch
+        events += MotionEvent.obtain(0, stretchTime, MotionEvent.ACTION_MOVE, x, yStretch, 0)
+        // hold
+        events += MotionEvent.obtain(0, endStretchTime, MotionEvent.ACTION_MOVE, x, yStretch, 0)
+
+        val yFling = (yStretch + yStart) / 2f
+        val yFlingHalf = (yStretch + yFling) / 2f
+        val flingHalfTime = endStretchTime + 10L
+        val flingTime = flingHalfTime + 10L
+
+        // fling
+        events += MotionEvent.obtain(0, flingHalfTime, MotionEvent.ACTION_MOVE, x, yFlingHalf, 0)
+        events += MotionEvent.obtain(0, flingTime, MotionEvent.ACTION_MOVE, x, yFling, 0)
+        events += MotionEvent.obtain(0, flingTime, MotionEvent.ACTION_UP, x, yFling, 0)
+
+        events.forEachIndexed { index, event ->
+            mRule.scenario.onActivity {
+                nestedScrollView.dispatchTouchEvent(event)
+                if (index == events.lastIndex) {
+                    onFlingStart()
+                }
+            }
+        }
+    }
+}
diff --git a/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java b/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
index 8e96af8..d738031 100644
--- a/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
+++ b/core/core/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
@@ -161,7 +161,7 @@
      * @param drawable The Drawable against which to invoke the method.
      * @param tintMode A Porter-Duff blending mode
      */
-    public static void setTintMode(@NonNull Drawable drawable, @NonNull PorterDuff.Mode tintMode) {
+    public static void setTintMode(@NonNull Drawable drawable, @Nullable PorterDuff.Mode tintMode) {
         if (Build.VERSION.SDK_INT >= 21) {
             Api21Impl.setTintMode(drawable, tintMode);
         } else if (drawable instanceof TintAwareDrawable) {
diff --git a/core/core/src/main/java/androidx/core/widget/NestedScrollView.java b/core/core/src/main/java/androidx/core/widget/NestedScrollView.java
index 4fa9e27..ff5861e 100644
--- a/core/core/src/main/java/androidx/core/widget/NestedScrollView.java
+++ b/core/core/src/main/java/androidx/core/widget/NestedScrollView.java
@@ -24,6 +24,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.hardware.SensorManager;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -82,6 +83,22 @@
     private static final int DEFAULT_SMOOTH_SCROLL_DURATION = 250;
 
     /**
+     * The following are copied from OverScroller to determine how far a fling will go.
+     */
+    private static final float SCROLL_FRICTION = 0.015f;
+    private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
+    private static final float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
+    private final float mPhysicalCoeff;
+
+    /**
+     * When flinging the stretch towards scrolling content, it should destretch quicker than the
+     * fling would normally do. The visual effect of flinging the stretch looks strange as little
+     * appears to happen at first and then when the stretch disappears, the content starts
+     * scrolling quickly.
+     */
+    private static final float FLING_DESTRETCH_FACTOR = 4f;
+
+    /**
      * Interface definition for a callback to be invoked when the scroll
      * X or Y positions of a view change.
      *
@@ -215,6 +232,12 @@
         mEdgeGlowTop = EdgeEffectCompat.create(context, attrs);
         mEdgeGlowBottom = EdgeEffectCompat.create(context, attrs);
 
+        final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
+        mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
+                * 39.37f // inch/meter
+                * ppi
+                * 0.84f; // look and feel tuning
+
         initScrollView();
 
         final TypedArray a = context.obtainStyledAttributes(
@@ -1014,12 +1037,86 @@
         return true;
     }
 
+    /**
+     * Returns true if edgeEffect should call onAbsorb() with veclocity or false if it should
+     * animate with a fling. It will animate with a fling if the velocity will remove the
+     * EdgeEffect through its normal operation.
+     *
+     * @param edgeEffect The EdgeEffect that might absorb the velocity.
+     * @param velocity The velocity of the fling motion
+     * @return true if the velocity should be absorbed or false if it should be flung.
+     */
+    private boolean shouldAbsorb(@NonNull EdgeEffect edgeEffect, int velocity) {
+        if (velocity > 0) {
+            return true;
+        }
+        float distance = EdgeEffectCompat.getDistance(edgeEffect) * getHeight();
+
+        // This is flinging without the spring, so let's see if it will fling past the overscroll
+        float flingDistance = getSplineFlingDistance(-velocity);
+
+        return flingDistance < distance;
+    }
+
+    /**
+     * If mTopGlow or mBottomGlow is currently active and the motion will remove some of the
+     * stretch, this will consume any of unconsumedY that the glow can. If the motion would
+     * increase the stretch, or the EdgeEffect isn't a stretch, then nothing will be consumed.
+     *
+     * @param unconsumedY The vertical delta that might be consumed by the vertical EdgeEffects
+     * @return The remaining unconsumed delta after the edge effects have consumed.
+     */
+    int consumeFlingInVerticalStretch(int unconsumedY) {
+        int height = getHeight();
+        if (unconsumedY > 0 && EdgeEffectCompat.getDistance(mEdgeGlowTop) != 0f) {
+            float deltaDistance = -unconsumedY * FLING_DESTRETCH_FACTOR / height;
+            int consumed = Math.round(-height / FLING_DESTRETCH_FACTOR
+                    * EdgeEffectCompat.onPullDistance(mEdgeGlowTop, deltaDistance, 0.5f));
+            if (consumed != unconsumedY) {
+                mEdgeGlowTop.finish();
+            }
+            return unconsumedY - consumed;
+        }
+        if (unconsumedY < 0 && EdgeEffectCompat.getDistance(mEdgeGlowBottom) != 0f) {
+            float deltaDistance = unconsumedY * FLING_DESTRETCH_FACTOR / height;
+            int consumed = Math.round(height / FLING_DESTRETCH_FACTOR
+                    * EdgeEffectCompat.onPullDistance(mEdgeGlowBottom, deltaDistance, 0.5f));
+            if (consumed != unconsumedY) {
+                mEdgeGlowBottom.finish();
+            }
+            return unconsumedY - consumed;
+        }
+        return unconsumedY;
+    }
+
+    /**
+     * Copied from OverScroller, this returns the distance that a fling with the given velocity
+     * will go.
+     * @param velocity The velocity of the fling
+     * @return The distance that will be traveled by a fling of the given velocity.
+     */
+    private float getSplineFlingDistance(int velocity) {
+        final double l =
+                Math.log(INFLEXION * Math.abs(velocity) / (SCROLL_FRICTION * mPhysicalCoeff));
+        final double decelMinusOne = DECELERATION_RATE - 1.0;
+        return (float) (SCROLL_FRICTION * mPhysicalCoeff
+                * Math.exp(DECELERATION_RATE / decelMinusOne * l));
+    }
+
     private boolean edgeEffectFling(int velocityY) {
         boolean consumed = true;
         if (EdgeEffectCompat.getDistance(mEdgeGlowTop) != 0) {
-            mEdgeGlowTop.onAbsorb(velocityY);
+            if (shouldAbsorb(mEdgeGlowTop, velocityY)) {
+                mEdgeGlowTop.onAbsorb(velocityY);
+            } else {
+                fling(-velocityY);
+            }
         } else if (EdgeEffectCompat.getDistance(mEdgeGlowBottom) != 0) {
-            mEdgeGlowBottom.onAbsorb(-velocityY);
+            if (shouldAbsorb(mEdgeGlowBottom, -velocityY)) {
+                mEdgeGlowBottom.onAbsorb(-velocityY);
+            } else {
+                fling(-velocityY);
+            }
         } else {
             consumed = false;
         }
@@ -1704,7 +1801,7 @@
 
         mScroller.computeScrollOffset();
         final int y = mScroller.getCurrY();
-        int unconsumed = y - mLastScrollerY;
+        int unconsumed = consumeFlingInVerticalStretch(y - mLastScrollerY);
         mLastScrollerY = y;
 
         // Nested Scrolling Pre Pass
diff --git a/datastore/datastore-multiprocess/build.gradle b/datastore/datastore-multiprocess/build.gradle
index 1b5e4313..30b35a7 100644
--- a/datastore/datastore-multiprocess/build.gradle
+++ b/datastore/datastore-multiprocess/build.gradle
@@ -25,6 +25,8 @@
 dependencies {
     api(libs.kotlinStdlib)
     api(libs.kotlinCoroutinesCore)
+    api("androidx.annotation:annotation:1.2.0")
+    api(project(":datastore:datastore-core"))
 
     androidTestImplementation(libs.junit)
     androidTestImplementation(libs.kotlinCoroutinesTest)
@@ -32,6 +34,8 @@
     androidTestImplementation(project(":internal-testutils-truth"))
     androidTestImplementation(libs.testRunner)
     androidTestImplementation(libs.testCore)
+    androidTestImplementation(project(":datastore:datastore-core"))
+    androidTestImplementation(project(":datastore:datastore-proto"))
 }
 
 android {
diff --git a/datastore/datastore-multiprocess/lint-baseline.xml b/datastore/datastore-multiprocess/lint-baseline.xml
index d56e146..b00c1cb 100644
--- a/datastore/datastore-multiprocess/lint-baseline.xml
+++ b/datastore/datastore-multiprocess/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha08)" variant="all" version="7.3.0-alpha08">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/datastore/datastore-multiprocess/src/main/AndroidManifest.xml b/datastore/datastore-multiprocess/src/main/AndroidManifest.xml
deleted file mode 100644
index 2aeafa4..0000000
--- a/datastore/datastore-multiprocess/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-  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.
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.datastore.multiprocess">
-
-</manifest>
diff --git a/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/MultiProcessDataStore.kt b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/MultiProcessDataStore.kt
new file mode 100644
index 0000000..51e4717
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/MultiProcessDataStore.kt
@@ -0,0 +1,447 @@
+/*
+ * 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.datastore.multiprocess
+
+import androidx.annotation.GuardedBy
+import androidx.datastore.core.CorruptionException
+import androidx.datastore.core.DataStore
+import androidx.datastore.core.Serializer
+import androidx.datastore.multiprocess.handlers.NoOpCorruptionHandler
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileNotFoundException
+import java.io.FileOutputStream
+import java.io.IOException
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.coroutineContext
+import kotlinx.coroutines.completeWith
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.dropWhile
+import kotlinx.coroutines.flow.emitAll
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.withContext
+
+/**
+ * Multi process implementation of DataStore. It is multi-process safe.
+ */
+// TODO(zhiyuanwang): copied straight from {@link androidx.datastore.core.SingleProcessDataStore},
+// replace with the real multi process implementation
+internal class MultiProcessDataStore<T>(
+    private val produceFile: () -> File,
+    private val serializer: Serializer<T>,
+    /**
+     * The list of initialization tasks to perform. These tasks will be completed before any data
+     * is published to the data and before any read-modify-writes execute in updateData.  If
+     * any of the tasks fail, the tasks will be run again the next time data is collected or
+     * updateData is called. Init tasks should not wait on results from data - this will
+     * result in deadlock.
+     */
+    initTasksList: List<suspend (api: InitializerApi<T>) -> Unit> = emptyList(),
+    private val corruptionHandler: CorruptionHandler<T> = NoOpCorruptionHandler<T>(),
+    private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
+) : DataStore<T> {
+
+    override val data: Flow<T> = flow {
+        /**
+         * If downstream flow is UnInitialized, no data has been read yet, we need to trigger a new
+         * read then start emitting values once we have seen a new value (or exception).
+         *
+         * If downstream flow has a ReadException, there was an exception last time we tried to read
+         * data. We need to trigger a new read then start emitting values once we have seen a new
+         * value (or exception).
+         *
+         * If downstream flow has Data, we should just start emitting from downstream flow.
+         *
+         * If Downstream flow is Final, the scope has been cancelled so the data store is no
+         * longer usable. We should just propagate this exception.
+         *
+         * State always starts at null. null can transition to ReadException, Data or
+         * Final. ReadException can transition to another ReadException, Data or Final.
+         * Data can transition to another Data or Final. Final will not change.
+         */
+
+        val currentDownStreamFlowState = downstreamFlow.value
+
+        if (currentDownStreamFlowState !is Data) {
+            // We need to send a read request because we don't have data yet.
+            actor.offer(Message.Read(currentDownStreamFlowState))
+        }
+
+        emitAll(
+            downstreamFlow.dropWhile {
+                if (currentDownStreamFlowState is Data<T> ||
+                    currentDownStreamFlowState is Final<T>
+                ) {
+                    // We don't need to drop any Data or Final values.
+                    false
+                } else {
+                    // we need to drop the last seen state since it was either an exception or
+                    // wasn't yet initialized. Since we sent a message to actor, we *will* see a
+                    // new value.
+                    it === currentDownStreamFlowState
+                }
+            }.map {
+                when (it) {
+                    is ReadException<T> -> throw it.readException
+                    is Final<T> -> throw it.finalException
+                    is Data<T> -> it.value
+                    is UnInitialized -> error(
+                        "This is a bug in DataStore. Please file a bug at: " +
+                            "https://issuetracker.google.com/issues/new?" +
+                            "component=907884&template=1466542"
+                    )
+                }
+            }
+        )
+    }
+
+    override suspend fun updateData(transform: suspend (t: T) -> T): T {
+        /**
+         * The states here are the same as the states for reads. Additionally we send an ack that
+         * the actor *must* respond to (even if it is cancelled).
+         */
+        val ack = CompletableDeferred<T>()
+        val currentDownStreamFlowState = downstreamFlow.value
+
+        val updateMsg =
+            Message.Update(transform, ack, currentDownStreamFlowState, coroutineContext)
+
+        actor.offer(updateMsg)
+
+        return ack.await()
+    }
+
+    private val SCRATCH_SUFFIX = ".tmp"
+
+    private val file: File by lazy {
+        val file = produceFile()
+
+        file.absolutePath.let {
+            synchronized(activeFilesLock) {
+                check(!activeFiles.contains(it)) {
+                    "There are multiple DataStores active for the same file: $file. You should " +
+                        "either maintain your DataStore as a singleton or confirm that there is " +
+                        "no two DataStore's active on the same file (by confirming that the scope" +
+                        " is cancelled)."
+                }
+                activeFiles.add(it)
+            }
+        }
+
+        file
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    private val downstreamFlow = MutableStateFlow(UnInitialized as State<T>)
+
+    private var initTasks: List<suspend (api: InitializerApi<T>) -> Unit>? =
+        initTasksList.toList()
+
+    /** The actions for the actor. */
+    private sealed class Message<T> {
+        abstract val lastState: State<T>?
+
+        /**
+         * Represents a read operation. If the data is already cached, this is a no-op. If data
+         * has not been cached, it triggers a new read to the specified dataChannel.
+         */
+        class Read<T>(
+            override val lastState: State<T>?
+        ) : Message<T>()
+
+        /** Represents an update operation. */
+        class Update<T>(
+            val transform: suspend (t: T) -> T,
+            /**
+             * Used to signal (un)successful completion of the update to the caller.
+             */
+            val ack: CompletableDeferred<T>,
+            override val lastState: State<T>?,
+            val callerContext: CoroutineContext
+        ) : Message<T>()
+    }
+
+    private val actor = SimpleActor<Message<T>>(
+        scope = scope,
+        onComplete = {
+            it?.let {
+                downstreamFlow.value = Final(it)
+            }
+            // We expect it to always be non-null but we will leave the alternative as a no-op
+            // just in case.
+
+            synchronized(activeFilesLock) {
+                activeFiles.remove(file.absolutePath)
+            }
+        },
+        onUndeliveredElement = { msg, ex ->
+            if (msg is Message.Update) {
+                // TODO(rohitsat): should we instead use scope.ensureActive() to get the original
+                //  cancellation cause? Should we instead have something like
+                //  UndeliveredElementException?
+                msg.ack.completeExceptionally(
+                    ex ?: CancellationException(
+                        "DataStore scope was cancelled before updateData could complete"
+                    )
+                )
+            }
+        }
+    ) { msg ->
+        when (msg) {
+            is Message.Read -> {
+                handleRead(msg)
+            }
+            is Message.Update -> {
+                handleUpdate(msg)
+            }
+        }
+    }
+
+    private suspend fun handleRead(read: Message.Read<T>) {
+        when (val currentState = downstreamFlow.value) {
+            is Data -> {
+                // We already have data so just return...
+            }
+            is ReadException -> {
+                if (currentState === read.lastState) {
+                    readAndInitOrPropagateFailure()
+                }
+
+                // Someone else beat us but also failed. The collector has already
+                // been signalled so we don't need to do anything.
+            }
+            UnInitialized -> {
+                readAndInitOrPropagateFailure()
+            }
+            is Final -> error("Can't read in final state.") // won't happen
+        }
+    }
+
+    private suspend fun handleUpdate(update: Message.Update<T>) {
+        // All branches of this *must* complete ack either successfully or exceptionally.
+        // We must *not* throw an exception, just propagate it to the ack.
+        update.ack.completeWith(
+            runCatching {
+
+                when (val currentState = downstreamFlow.value) {
+                    is Data -> {
+                        // We are already initialized, we just need to perform the update
+                        transformAndWrite(update.transform, update.callerContext)
+                    }
+                    is ReadException, is UnInitialized -> {
+                        if (currentState === update.lastState) {
+                            // we need to try to read again
+                            readAndInitOrPropagateAndThrowFailure()
+
+                            // We've successfully read, now we need to perform the update
+                            transformAndWrite(update.transform, update.callerContext)
+                        } else {
+                            // Someone else beat us to read but also failed. We just need to
+                            // signal the writer that is waiting on ack.
+                            // This cast is safe because we can't be in the UnInitialized
+                            // state if the state has changed.
+                            throw (currentState as ReadException).readException
+                        }
+                    }
+
+                    is Final -> throw currentState.finalException // won't happen
+                }
+            }
+        )
+    }
+
+    private suspend fun readAndInitOrPropagateAndThrowFailure() {
+        try {
+            readAndInit()
+        } catch (throwable: Throwable) {
+            downstreamFlow.value = ReadException(throwable)
+            throw throwable
+        }
+    }
+
+    private suspend fun readAndInitOrPropagateFailure() {
+        try {
+            readAndInit()
+        } catch (throwable: Throwable) {
+            downstreamFlow.value = ReadException(throwable)
+        }
+    }
+
+    private suspend fun readAndInit() {
+        // This should only be called if we don't already have cached data.
+        check(downstreamFlow.value == UnInitialized || downstreamFlow.value is ReadException)
+
+        val updateLock = Mutex()
+        var initData = readDataOrHandleCorruption()
+
+        var initializationComplete: Boolean = false
+
+        // TODO(b/151635324): Consider using Context Element to throw an error on re-entrance.
+        val api = object : InitializerApi<T> {
+            override suspend fun updateData(transform: suspend (t: T) -> T): T {
+                return updateLock.withLock() {
+                    if (initializationComplete) {
+                        throw IllegalStateException(
+                            "InitializerApi.updateData should not be " +
+                                "called after initialization is complete."
+                        )
+                    }
+
+                    val newData = transform(initData)
+                    if (newData != initData) {
+                        writeData(newData)
+                        initData = newData
+                    }
+
+                    initData
+                }
+            }
+        }
+
+        initTasks?.forEach { it(api) }
+        initTasks = null // Init tasks have run successfully, we don't need them anymore.
+        updateLock.withLock {
+            initializationComplete = true
+        }
+
+        downstreamFlow.value = Data(initData, initData.hashCode(), /* unused */ version = 0)
+    }
+
+    private suspend fun readDataOrHandleCorruption(): T {
+        try {
+            return readData()
+        } catch (ex: CorruptionException) {
+
+            val newData: T = corruptionHandler.handleCorruption(ex)
+
+            try {
+                writeData(newData)
+            } catch (writeEx: IOException) {
+                // If we fail to write the handled data, add the new exception as a suppressed
+                // exception.
+                ex.addSuppressed(writeEx)
+                throw ex
+            }
+
+            // If we reach this point, we've successfully replaced the data on disk with newData.
+            return newData
+        }
+    }
+
+    private suspend fun readData(): T {
+        try {
+            FileInputStream(file).use { stream ->
+                return serializer.readFrom(stream)
+            }
+        } catch (ex: FileNotFoundException) {
+            if (file.exists()) {
+                throw ex
+            }
+            return serializer.defaultValue
+        }
+    }
+
+    // downstreamFlow.value must be successfully set to data before calling this
+    private suspend fun transformAndWrite(
+        transform: suspend (t: T) -> T,
+        callerContext: CoroutineContext
+    ): T {
+        // value is not null or an exception because we must have the value set by now so this cast
+        // is safe.
+        val curDataAndHash = downstreamFlow.value as Data<T>
+        curDataAndHash.checkHashCode()
+
+        val curData = curDataAndHash.value
+        val newData = withContext(callerContext) { transform(curData) }
+
+        // Check that curData has not changed...
+        curDataAndHash.checkHashCode()
+
+        return if (curData == newData) {
+            curData
+        } else {
+            writeData(newData)
+            downstreamFlow.value = Data(newData, newData.hashCode(), /* unused */ version = 0)
+            newData
+        }
+    }
+
+    /**
+     * Internal only to prevent creation of synthetic accessor function. Do not call this from
+     * outside this class.
+     */
+    internal suspend fun writeData(newData: T) {
+        file.createParentDirectories()
+
+        val scratchFile = File(file.absolutePath + SCRATCH_SUFFIX)
+        try {
+            FileOutputStream(scratchFile).use { stream ->
+                serializer.writeTo(newData, UncloseableOutputStream(stream))
+                stream.fd.sync()
+                // TODO(b/151635324): fsync the directory, otherwise a badly timed crash could
+                //  result in reverting to a previous state.
+            }
+
+            if (!scratchFile.renameTo(file)) {
+                throw IOException(
+                    "Unable to rename $scratchFile." +
+                        "This likely means that there are multiple instances of DataStore " +
+                        "for this file. Ensure that you are only creating a single instance of " +
+                        "datastore for this file."
+                )
+            }
+        } catch (ex: IOException) {
+            if (scratchFile.exists()) {
+                scratchFile.delete() // Swallow failure to delete
+            }
+            throw ex
+        }
+    }
+
+    private fun File.createParentDirectories() {
+        val parent: File? = canonicalFile.parentFile
+
+        parent?.let {
+            it.mkdirs()
+            if (!it.isDirectory) {
+                throw IOException("Unable to create parent directories of $this")
+            }
+        }
+    }
+
+    internal companion object {
+        /**
+         * Active files should contain the absolute path for which there are currently active
+         * DataStores. A DataStore is active until the scope it was created with has been
+         * cancelled. Files aren't added to this list until the first read/write because the file
+         * path is computed asynchronously.
+         */
+        @GuardedBy("activeFilesLock")
+        internal val activeFiles = mutableSetOf<String>()
+
+        internal val activeFilesLock = Any()
+    }
+}
\ No newline at end of file
diff --git a/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/handlers/NoOpCorruptionHandler.kt b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/handlers/NoOpCorruptionHandler.kt
new file mode 100644
index 0000000..c92e910
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/handlers/NoOpCorruptionHandler.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.datastore.multiprocess.handlers
+
+import androidx.datastore.core.CorruptionException
+import androidx.datastore.multiprocess.CorruptionHandler
+
+/**
+ * Default corruption handler which does nothing but rethrow the exception.
+ */
+internal class NoOpCorruptionHandler<T> : CorruptionHandler<T> {
+
+    @Throws(CorruptionException::class)
+    override suspend fun handleCorruption(ex: CorruptionException): T {
+        throw ex
+    }
+}
\ No newline at end of file
diff --git a/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/CorruptionHandler.kt b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/CorruptionHandler.kt
new file mode 100644
index 0000000..1eacf02
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/CorruptionHandler.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.datastore.multiprocess
+
+import androidx.datastore.core.CorruptionException
+
+/**
+ * CorruptionHandlers allow recovery from corruption that prevents reading data from the file (as
+ * indicated by a CorruptionException).
+ */
+internal interface CorruptionHandler<T> {
+    /**
+     * This function will be called by DataStore when it encounters corruption. If the
+     * implementation of this function throws an exception, it will be propagated to the original
+     * call to DataStore. Otherwise, the returned data will be written to disk.
+     *
+     * This function should not interact with any DataStore API - doing so can result in a deadlock.
+     *
+     * @param ex is the exception encountered when attempting to deserialize data from disk.
+     * @return The value that DataStore should attempt to write to disk.
+     **/
+    public suspend fun handleCorruption(ex: CorruptionException): T
+}
\ No newline at end of file
diff --git a/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/InitializerApi.kt b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/InitializerApi.kt
new file mode 100644
index 0000000..c7eaa410
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/InitializerApi.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.datastore.multiprocess
+
+/**
+ * The initializer API allows changes to be made to store before data is accessed through
+ * data or updateData.
+ *
+ * Initializers are executed in the order in which they are added. They must be idempotent
+ * since they are run each time the DataStore starts, and they may be run multiple times by a
+ * single instance if a downstream initializer fails.
+ *
+ * Note: Initializers are internal only. Instead, see [DataMigration].
+ */
+internal interface InitializerApi<T> {
+    suspend fun updateData(transform: suspend (t: T) -> T): T
+}
\ No newline at end of file
diff --git a/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/Message.kt b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/Message.kt
new file mode 100644
index 0000000..b3ae931
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/Message.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.datastore.multiprocess
+
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CompletableDeferred
+
+/** The actions for the actor. */
+internal sealed class Message<T> {
+    abstract val lastState: State<T>?
+
+    /**
+     * Represents a read operation. If the data is already cached, this is a no-op. If data
+     * has not been cached, it triggers a new read to the specified dataChannel.
+     */
+    class Read<T>(
+        override val lastState: State<T>?,
+        val isBlocking: Boolean = false
+    ) : Message<T>()
+
+    /** Represents an update operation. */
+    class Update<T>(
+        val transform: suspend (t: T) -> T,
+        /**
+         * Used to signal (un)successful completion of the update to the caller.
+         */
+        val ack: CompletableDeferred<T>,
+        override val lastState: State<T>?,
+        val callerContext: CoroutineContext
+    ) : Message<T>()
+}
\ No newline at end of file
diff --git a/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/SimpleActor.kt b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/SimpleActor.kt
new file mode 100644
index 0000000..39f3a38
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/SimpleActor.kt
@@ -0,0 +1,127 @@
+/*
+ * 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.datastore.multiprocess
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
+import kotlinx.coroutines.channels.ClosedSendChannelException
+import kotlinx.coroutines.channels.onClosed
+import kotlinx.coroutines.ensureActive
+import kotlinx.coroutines.launch
+import java.util.concurrent.atomic.AtomicInteger
+
+internal class SimpleActor<T>(
+    /**
+     * The scope in which to consume messages.
+     */
+    private val scope: CoroutineScope,
+    /**
+     * Function that will be called when scope is cancelled. Should *not* throw exceptions.
+     */
+    onComplete: (Throwable?) -> Unit,
+    /**
+     * Function that will be called for each element when the scope is cancelled. Should *not*
+     * throw exceptions.
+     */
+    onUndeliveredElement: (T, Throwable?) -> Unit,
+    /**
+     * Function that will be called once for each message.
+     *
+     * Must *not* throw an exception (other than CancellationException if scope is cancelled).
+     */
+    private val consumeMessage: suspend (T) -> Unit
+) {
+    private val messageQueue = Channel<T>(capacity = UNLIMITED)
+
+    /**
+     * Count of the number of remaining messages to process. When the messageQueue is closed,
+     * this is no longer used.
+     */
+    private val remainingMessages = AtomicInteger(0)
+
+    init {
+        // If the scope doesn't have a job, it won't be cancelled, so we don't need to register a
+        // callback.
+        scope.coroutineContext[Job]?.invokeOnCompletion { ex ->
+            onComplete(ex)
+
+            // TODO(rohitsat): replace this with Channel(onUndeliveredElement) when it
+            // is fixed: https://github.com/Kotlin/kotlinx.coroutines/issues/2435
+
+            messageQueue.close(ex)
+
+            while (true) {
+                messageQueue.tryReceive().getOrNull()?.let { msg ->
+                    onUndeliveredElement(msg, ex)
+                } ?: break
+            }
+        }
+    }
+
+    /**
+     * Sends a message to a message queue to be processed by [consumeMessage] in [scope].
+     *
+     * If [offer] completes successfully, the msg *will* be processed either by
+     * consumeMessage or
+     * onUndeliveredElement. If [offer] throws an exception, the message may or may not be
+     * processed.
+     */
+    fun offer(msg: T) {
+        /**
+         * Possible states:
+         * 1) remainingMessages = 0
+         *   All messages have been consumed, so there is no active consumer
+         * 2) remainingMessages > 0, no active consumer
+         *   One of the senders is responsible for triggering the consumer
+         * 3) remainingMessages > 0, active consumer
+         *   Consumer will continue to consume until remainingMessages is 0
+         * 4) messageQueue is closed, there are remaining messages to consume
+         *   Attempts to offer messages will fail, onComplete() will consume remaining messages
+         *   with onUndelivered. The Consumer has already completed since close() is called by
+         *   onComplete().
+         * 5) messageQueue is closed, there are no remaining messages to consume
+         *   Attempts to offer messages will fail.
+         */
+
+        // should never return false bc the channel capacity is unlimited
+        check(
+            messageQueue.trySend(msg)
+                .onClosed { throw it ?: ClosedSendChannelException("Channel was closed normally") }
+                .isSuccess
+        )
+
+        // If the number of remaining messages was 0, there is no active consumer, since it quits
+        // consuming once remaining messages hits 0. We must kick off a new consumer.
+        if (remainingMessages.getAndIncrement() == 0) {
+            scope.launch {
+                // We shouldn't have started a new consumer unless there are remaining messages...
+                check(remainingMessages.get() > 0)
+
+                do {
+                    // We don't want to try to consume a new message unless we are still active.
+                    // If ensureActive throws, the scope is no longer active, so it doesn't
+                    // matter that we have remaining messages.
+                    scope.ensureActive()
+
+                    consumeMessage(messageQueue.receive())
+                } while (remainingMessages.decrementAndGet() != 0)
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/State.kt b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/State.kt
new file mode 100644
index 0000000..c83819b
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/State.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.datastore.multiprocess
+
+/**
+ * Represents the current state of the DataStore.
+ */
+internal sealed class State<T>
+
+internal object UnInitialized : State<Any>()
+
+/**
+ * A read from disk has succeeded, value represents the current on disk state.
+ */
+internal class Data<T>(val value: T, val hashCode: Int, val version: Int) : State<T>() {
+    fun checkHashCode() {
+        check(value.hashCode() == hashCode) {
+            "Data in DataStore was mutated but DataStore is only compatible with Immutable types."
+        }
+    }
+}
+
+/**
+ * A read from disk has failed. ReadException is the exception that was thrown.
+ */
+internal class ReadException<T>(val readException: Throwable) : State<T>()
+
+/**
+ * The scope has been cancelled. This DataStore cannot process any new reads or writes.
+ */
+internal class Final<T>(val finalException: Throwable) : State<T>()
\ No newline at end of file
diff --git a/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/UncloseableOutputStream.kt b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/UncloseableOutputStream.kt
new file mode 100644
index 0000000..45b1c81
--- /dev/null
+++ b/datastore/datastore-multiprocess/src/main/java/androidx/datastore/multiprocess/internal/UncloseableOutputStream.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.datastore.multiprocess
+
+import java.io.FileOutputStream
+import java.io.OutputStream
+
+/**
+ * Wrapper on FileOutputStream to prevent closing the underlying OutputStream.
+ */
+internal class UncloseableOutputStream(val fileOutputStream: FileOutputStream) : OutputStream() {
+
+    override fun write(b: Int) {
+        fileOutputStream.write(b)
+    }
+
+    override fun write(b: ByteArray) {
+        fileOutputStream.write(b)
+    }
+
+    override fun write(bytes: ByteArray, off: Int, len: Int) {
+        fileOutputStream.write(bytes, off, len)
+    }
+
+    override fun close() {
+        // We will not close the underlying FileOutputStream until after we're done syncing
+        // the fd. This is useful for things like b/173037611.
+    }
+
+    override fun flush() {
+        fileOutputStream.flush()
+    }
+}
\ No newline at end of file
diff --git a/datastore/datastore-sampleapp/lint-baseline.xml b/datastore/datastore-sampleapp/lint-baseline.xml
deleted file mode 100644
index 937c82f..0000000
--- a/datastore/datastore-sampleapp/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="LongLogTag"
-        message="The logging tag can be at most 23 characters, was 27 (KotlinSerializationActivity)"
-        errorLine1="                        Log.e(TAG, &quot;Error reading preferences.&quot;, e)"
-        errorLine2="                              ~~~">
-        <location
-            file="src/main/java/com/example/datastoresampleapp/KotlinSerializationActivity.kt"/>
-    </issue>
-
-</issues>
diff --git a/datastore/settings.gradle b/datastore/settings.gradle
index 4fcda2f..1b88d33 100644
--- a/datastore/settings.gradle
+++ b/datastore/settings.gradle
@@ -31,6 +31,7 @@
         if (name == ":datastore:datastore-compose-samples") return false
         if (name.startsWith(":datastore")) return true
         if (name == ":annotation:annotation-sampled") return true
+        if (name == ":internal-testutils-datastore") return true
         if (name == ":internal-testutils-kmp") return true
         if (name == ":internal-testutils-truth") return true
         return false
diff --git a/development/build_log_simplifier/message-flakes.ignore b/development/build_log_simplifier/message-flakes.ignore
index 4999faa..15a5ba5 100644
--- a/development/build_log_simplifier/message-flakes.ignore
+++ b/development/build_log_simplifier/message-flakes.ignore
@@ -31,10 +31,21 @@
 [0-9]+ actionable task: [0-9]+ executed
 [0-9]+ actionable tasks: [0-9]+ executed, [0-9]+ from cache, [0-9]+ up\-to\-date
 The remote build cache was disabled during the build due to errors\.
+The build is running offline\. A build scan will not be published at this time, but it can be published if you run the buildScanPublishPrevious task in the next build\.
+Calculating task graph as configuration cache cannot be reused because environment variable '.*' has changed\.
+Calculating task graph as configuration cache cannot be reused because file '[^ ]*' has changed\.
+Calculating task graph as no configuration cache is available for tasks:.*
+Reusing configuration cache\.
+Calculating task graph as configuration cache cannot be reused because an input to task '[^ ]*' has changed\.
+See the profiling report at\: file\:\/\/\$OUT_DIR\/buildSrc\/build\/reports\/profile\/profile\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\.html
 # Some messages that encode the number of a certain type of other error
 [0-9]+ errors, [0-9]+ warnings \([0-9]+ warnings filtered by baseline lint\-baseline\.xml\)
 [0-9]+ errors, [0-9]+ warnings \([0-9]+ warning filtered by baseline lint\-baseline\.xml\)
 [0-9]+ problems were found reusing the configuration cache, [0-9]+ of which seems unique\.
+[0-9]+ problems were found storing the configuration cache, [0-9]+ of which seems unique\.
+[0-9]+ problems were found reusing the configuration cache\.
+[0-9]+ problem was found reusing the configuration cache\.
+Configuration cache entry reused with [0-9]+ problem\.
 # > Task :webkit:integration-tests:testapp:compileReleaseJavaWithJavac
 \[ant\:jacocoReport\] Note\: Some input files use or override a deprecated API\.
 \[ant\:jacocoReport\] Note\: Recompile with \-Xlint\:deprecation for details\.
@@ -134,3 +145,5 @@
 Using custom version .* of AGP due to GRADLE_PLUGIN_VERSION being set\.
 Using custom version .* of Lint due to LINT_VERSION being set\.
 Using custom version .* of metalava due to METALAVA_VERSION being set\.
+Publishing build scan\.\.\.
+https://ge\.androidx\.dev/s/.*
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index 376a686..070a903 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -5,9 +5,7 @@
 # > Task :docs-runner:dokkaJavaPublicDocs
 (logging: loading modules: \[java\.se.*)|(.*No file found when processing Java @sample.*)
 .*\.kotlin_module: error: module was compiled with an incompatible version of Kotlin\. The binary version of its metadata is [0-9]+\.[0-9]+\.[0-9]+, expected version is [0-9]+\.[0-9]+\.[0-9]+\.
-WARN: The registry key 'java\.correct\.class\.type\.by\.place\.resolve\.scope' accessed, but not loaded yet
 WARN: Attempt to load key 'java\.correct\.class\.type\.by\.place\.resolve\.scope' for not yet loaded registry
-PROGRESS: Rendering
 No docs found on supertype with \{@inheritDoc\} method .*
 Can't find node by signature .*
 Exception while resolving link to Module: Package:androidx\.datastore\.core GroupNode:IOException
@@ -134,43 +132,22 @@
 # > Configure project :appsearch:appsearch\-local\-backend
 Configuration on demand is an incubating feature\.
 Configuration cache is an incubating feature\.
-Calculating task graph as configuration cache cannot be reused because environment variable '.*' has changed\.
-Calculating task graph as configuration cache cannot be reused because file '[^ ]*' has changed\.
-Calculating task graph as no configuration cache is available for tasks:.*
-Reusing configuration cache\.
-Calculating task graph as configuration cache cannot be reused because an input to task '[^ ]*' has changed\.
-Type\-safe dependency accessors is an incubating feature\.
-The build is running offline\. A build scan will not be published at this time, but it can be published if you run the buildScanPublishPrevious task in the next build\.
 # > Configure project :
 updated local\.properties
 # > Configure project :compose:test\-utils
 The following Kotlin source sets were configured but not added to any Kotlin compilation:
-\* iosArm[0-9]+Test
-\* iosX[0-9]+Test
-\* linuxX[0-9]+Test
-\* macosX[0-9]+Test
-\* mingwX[0-9]+Test
-\* nativeTest
 \* androidAndroidTestRelease
 \* androidTestFixtures
 \* androidTestFixturesDebug
 \* androidTestFixturesRelease
 \* androidTestRelease
-\* test
 You can add a source set to a target's compilation by connecting it with the compilation's default source set using 'dependsOn'\.
 See https://kotlinlang\.org/docs/reference/building\-mpp\-with\-gradle\.html\#connecting\-source\-sets
-\* jvmMain
 # > Task :listTaskOutputs
 Wrote \$DIST_DIR/task_outputs\.txt
-[0-9]+ problem was found reusing the configuration cache\.
 Deprecated Gradle features were used in this build, making it incompatible with Gradle [0-9]+\.[0-9]+\.
 See https://docs.gradle.org/.*/userguide/command_line_interface\.html#sec:command_line_warnings
-Execution optimizations have been disabled for [0-9]+ invalid unit\(s\) of work during this build to ensure correctness\.
-Please consult deprecation warnings for more details\.
 BUILD SUCCESSFUL in .*
-Publishing build scan\.\.\.
-https://ge\.androidx\.dev/s/.*
-Configuration cache entry reused with [0-9]+ problem\.
 # > Task :doclava:compileJava
 Note\: Some input files use or override a deprecated API\.
 Note: Some input files use or override a deprecated API that is marked for removal\.
@@ -180,1167 +157,56 @@
 # > Task :ui:ui-tooling:processDebugAndroidTestManifest
 application@android:debuggable was tagged at .*\.xml:[0-9]+ to replace other declarations but no other declaration present
 \$OUT_DIR/androidx/benchmark/integration\-tests/dry\-run\-benchmark/build/intermediates/tmp/manifest/androidTest/release/tempFile[0-9]+ProcessTestManifest[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :compose:foundation:foundation-layout:processDebugAndroidTestManifest
-\$SUPPORT/compose/foundation/foundation\-layout/src/androidAndroidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
 # > Task :compose:runtime:runtime-saveable:processDebugAndroidTestManifest
 \$SUPPORT/compose/runtime/runtime\-saveable/src/androidAndroidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :compose:runtime:runtime:benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/compose/runtime/runtime/compose\-runtime\-benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :compose:ui:ui:compileKotlinMetadata
-w: Runtime JAR files in the classpath should have the same version\. These files were found in the classpath:
-w: Consider providing an explicit dependency on kotlin\-reflect [0-9]+\.[0-9]+ to prevent strange errors
-\$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-stdlib/[0-9]+\.[0-9]+\.[0-9]+-?[\-A-Z0-9]*/kotlin\-stdlib\-[0-9]+\.[0-9]+\.[0-9]+-?[\-A-Z0-9]*\.jar \(version [0-9]+\.[0-9]+-?[\-A-Z0-9]*\)
-\$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-reflect/[0-9]+\.[0-9]+\.[0-9]+-?[\-A-Z0-9]*/kotlin\-reflect\-[0-9]+\.[0-9]+\.[0-9]+-?[\-A-Z0-9]*\.jar \(version [0-9]+\.[0-9]+-?[\-A-Z0-9]*\)
-\$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-script-runtime/[0-9]+\.[0-9]+\.[0-9]+-?[\-A-Z0-9]*/kotlin\-script-runtime\-[0-9]+\.[0-9]+\.[0-9]+-?[\-A-Z0-9]*\.jar \(version [0-9]+\.[0-9]+-?[\-A-Z0-9]*\)
-\$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-stdlib\-common/[0-9]+\.[0-9]+\.[0-9]+-?[\-A-Z0-9]*/kotlin\-stdlib\-common\-[0-9]+\.[0-9]+\.[0-9]+-?[\-A-Z0-9]*\.jar \(version [0-9]+\.[0-9]+-?[\-A-Z0-9]*\)
-w: Some runtime JAR files in the classpath have an incompatible version\. Consider removing them from the classpath
-w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DepthSortedSet\.kt: \([0-9]+, [0-9]+\): The corresponding parameter in the supertype 'Comparator' is named 'a'\. This may cause problems when calling this function with named arguments\.
-w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DepthSortedSet\.kt: \([0-9]+, [0-9]+\): The corresponding parameter in the supertype 'Comparator' is named 'b'\. This may cause problems when calling this function with named arguments\.
-# > Task :benchmark:benchmark-common:runErrorProne
-\^
-symbol:   class OnBackInvokedCallback
-location: package android\.view
-import android\.view\.OnBackInvokedDispatcher;
-symbol:   class OnBackInvokedDispatcher
-private OnBackInvokedCallback mOnBackInvokedCallback;
-location: class OnBackPressedDispatcher
-private OnBackInvokedDispatcher mInvokedDispatcher;
-public void setOnBackPressedInvoker\(@NonNull OnBackInvokedDispatcher invoker\) \{
-OnBackInvokedDispatcher onBackInvokedDispatcher,
-location: class Api[0-9]+Impl
-OnBackInvokedCallback onBackInvokedCallback, int priority
-OnBackInvokedCallback onBackInvokedCallback
-public abstract void jvmDelete\(T t\);
-public abstract void jvmInsert\(@org\.jetbrains\.annotations\.NotNull\(\)
-public abstract java\.util\.List<androidx\.room\.androidx\.room\.integration\.kotlintestapp\.test\.JvmNameInDaoTest\.JvmNameEntity> jvmQuery\(\);
-symbol\:   static FLAG_MUTABLE
-location\: class PendingIntent
-\$OUT_DIR\/androidx\/docs\-public\/build\/srcs\/androidx\/work\/impl\/utils\/ForceStopRunnable\.java\:[0-9]+\: error\: cannot find symbol
 # > Task :buildOnServer
-[0-9]+ problems were found reusing the configuration cache\.
-[0-9]+ problems were found reusing the configuration cache, [0-9]+ of which seem unique\.
 [0-9]+ actionable tasks: [0-9]+ executed, [0-9]+ up\-to\-date
 Configuration cache entry reused with [0-9]+ problems\.
 See the profiling report at: file://\$GRADLE_USER_HOME/daemon/.*/reports/profile/profile\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\.html
 Configuration cache entry reused\.
 Configuration cache entry stored with [0-9]+ problems\.
-Configuration cache entry stored with [0-9] problem\.
 [0-9]+ actionable tasks: [0-9]+ executed, [0-9]+ from cache
-WARNING: [0-9]+ build scan custom values were not captured:
-\- Maximum number of custom values \([0-9]+,[0-9]+\) exceeded: [:A-Za-z0-9#\-]+
-A build scan will not be published due to this build running offline\.
 Configuration cache entry stored\.
 See the profiling report at\: file\:\/\/\$OUT_DIR\/androidx\/build\/reports\/profile\/profile\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\.html
-See the profiling report at\: file\:\/\/\$OUT_DIR\/gradle\/external\/doclava\/build\/reports\/profile\/profile\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\.html
 # > Task :lifecycle:lifecycle-common:compileJava
 Note: \$[^ ]+ uses or overrides a deprecated API\.
 Note: Recompile with \-Xlint\:deprecation for details\.
-Note: \$SUPPORT/samples/Support7Demos/src/main/java/com/example/android/supportv[0-9]+/util/DiffUtilActivity\.java uses unchecked or unsafe operations\.
-# > Task :publicDocsTask
-[0-9]+ warnings
+Note: \$SUPPORT/room/integration\-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/TestUtil\.java uses unchecked or unsafe operations\.
 # > Task :startup:integration-tests:first-library:processDebugManifest
 \$SUPPORT/startup/integration\-tests/first\-library/src/main/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
 meta\-data\#androidx\.work\.WorkManagerInitializer was tagged at AndroidManifest\.xml\:[0-9]+ to remove other declarations but no other declaration present
 # > Task :support-slices-demos:compileDebugJavaWithJavac
 Note: \$SUPPORT/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser\.java uses unchecked or unsafe operations\.
-# > Task :emoji2:emoji2-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/emoji[0-9]+/emoji[0-9]+\-benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :leanback:leanback:compileDebugAndroidTestJavaWithJavac
-reason: class file for kotlin\.annotation\.AnnotationTarget not found
-warning: unknown enum constant AnnotationTarget\.PROPERTY
-warning: unknown enum constant AnnotationTarget\.LOCAL_VARIABLE
-warning: unknown enum constant AnnotationTarget\.VALUE_PARAMETER
-warning: unknown enum constant AnnotationTarget\.CONSTRUCTOR
-warning: unknown enum constant AnnotationTarget\.FUNCTION
-warning: unknown enum constant AnnotationTarget\.PROPERTY_GETTER
-warning: unknown enum constant AnnotationTarget\.PROPERTY_SETTER
-warning: unknown enum constant AnnotationTarget\.FILE
-warning: unknown enum constant AnnotationTarget\.TYPEALIAS
-reason: class file for kotlin\.annotation\.AnnotationRetention not found
-warning: unknown enum constant AnnotationTarget\.CLASS
-warning: unknown enum constant AnnotationTarget\.ANNOTATION_CLASS
-# > Task :recyclerview:recyclerview-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/recyclerview/recyclerview\-benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :room:room-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/room/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :room:room-benchmark:kaptReleaseAndroidTestKotlin
-\$OUT_DIR/androidx/room/room\-benchmark/build/tmp/kapt[0-9]+/stubs/releaseAndroidTest/androidx/room/benchmark/RelationBenchmark\.java:[0-9]+: warning: The return value includes a POJO with a @Relation\. It is usually desired to annotate this method with @Transaction to avoid possibility of inconsistent results between the POJO and its relations\. See https://developer\.android\.com/reference/androidx/room/Transaction\.html for details\.
-public abstract java\.util\.List<androidx\.room\.benchmark\.RelationBenchmark\.UserWithItems> getUserWithItems\(\);
-# > Task :room:integration-tests:room-testapp-noappcompat:compileDebugAndroidTestJavaWithJavac
-\$SUPPORT/room/integration\-tests/noappcompattestapp/src/androidTest/java/androidx/room/integration/noappcompat/BareRelationDatabaseTest\.java:[0-9]+: warning: The return value includes a POJO with a @Relation\. It is usually desired to annotate this method with @Transaction to avoid possibility of inconsistent results between the POJO and its relations\. See https://developer\.android\.com/reference/androidx/room/Transaction\.html for details\.
-UserAndPets getUserWithPets\(long id\);
-List<UserAndPet> getUsersWithPet\(\);
-# > Task :room:integration-tests:room-testapp:compileDebugAndroidTestJavaWithJavac
-Note: \$SUPPORT/room/integration\-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/TestUtil\.java uses unchecked or unsafe operations\.
 # > Task :activity:integration-tests:testapp:processDebugAndroidTestManifest
 # b/166471969
-\$SUPPORT/appcompat/appcompat\-benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-\$SUPPORT/benchmark/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-\$SUPPORT/collection/collection\-benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-\$SUPPORT/navigation/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-\$SUPPORT/work/workmanager\-benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
 \$SUPPORT/benchmark/integration\-tests/dry\-run\-benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-\$SUPPORT/benchmark/integration\-tests/startup\-benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :leanback:leanback-paging:generateApi
-w\: Runtime JAR files in the classpath have the version [0-9]+\.[0-9]+\, which is older than the API version [0-9]+\.[0-9]+\. Consider using the runtime of version [0-9]+\.[0-9]+\, or pass \'\-api\-version [0-9]+\.[0-9]+\' explicitly to restrict the available APIs to the runtime of version [0-9]+\.[0-9]+\. You can also pass \'\-language\-version [0-9]+\.[0-9]+\' instead\, which will restrict not only the APIs to the specified version\, but also the language features
-w: \$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-stdlib\-jdk[0-9]+/[0-9]+\.[0-9]+\.[0-9]+/kotlin\-stdlib\-jdk[0-9]+\-[0-9]+\.[0-9]+\.[0-9]+\.jar: Runtime JAR file has version [0-9]+\.[0-9]+ which is older than required for API version [0-9]+\.[0-9]+
-w: \$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-reflect/[0-9]+\.[0-9]+\.[0-9]+/kotlin\-reflect\-[0-9]+\.[0-9]+\.[0-9]+\.jar: Runtime JAR file has version [0-9]+\.[0-9]+ which is older than required for API version [0-9]+\.[0-9]+
-w\: \$CHECKOUT\/prebuilts\/androidx\/external\/org\/jetbrains\/kotlin\/kotlin\-stdlib\/[0-9]+\.[0-9]+\.[0-9]+\/kotlin\-stdlib\-[0-9]+\.[0-9]+\.[0-9]+\.jar\: Runtime JAR file has version [0-9]+\.[0-9]+ which is older than required for API version [0-9]+\.[0-9]+
-w\: \$CHECKOUT\/prebuilts\/androidx\/external\/org\/jetbrains\/kotlin\/kotlin\-stdlib\-common\/[0-9]+\.[0-9]+\.[0-9]+\/kotlin\-stdlib\-common\-[0-9]+\.[0-9]+\.[0-9]+\.jar\: Runtime JAR file has version [0-9]+\.[0-9]+ which is older than required for API version [0-9]+\.[0-9]+
 # > Task :compose:material:material:icons:generator:zipHtmlResultsOfTest
 Html results of .* zipped into.*\.zip
-# https://github.com/gradle/common-custom-user-data-gradle-plugin/issues/44
-See https://docs\.gradle\.org/[0-9]+\.[0-9]+.*/userguide/configuration_cache\.html\#config_cache:requirements:external_processes
-\- Class `com\.gradle\.Utils`: external process started .*
 # b/230127926
-\- Plugin 'com\.android\.internal\.application': external process started .*
-\- Plugin 'com\.android\.internal\.library': external process started .*
 [0-9]+ problems were found storing the configuration cache, [0-9]+ of which seem unique\.
 \- Task `:[:A-Za-z0-9#\-]+` of type `org\.jetbrains\.kotlin\.gradle\.plugin\.mpp\.[A-Za-z0-9]+`: invocation of 'Task\.project' at execution time is unsupported\.
 # https://youtrack.jetbrains.com/issue/KT-52694/
-\- Task `:[:A-Za-z0-9#\-]+` of type `org\.jetbrains\.kotlin\.gradle\.tooling\.BuildKotlinToolingMetadataTask$FromKotlinExtension`: invocation of 'Task\.project' at execution time is unsupported\.
-See https://docs\.gradle\.org/[0-9]+\.[0-9]+.*/userguide/configuration_cache\.html\#config_cache:requirements:disallowed_types
-[0-9]+ problem was found storing the configuration cache.
 \- Task `:listTaskOutputs` of type `androidx\.build\.ListTaskOutputsTask`: invocation of 'Task\.project' at execution time is unsupported\.
-\- Task `[^ ]*checkExternalLicenses` of type `[^ ]*CheckExternalDependencyLicensesTask`: invocation of 'Task\.project' at execution time is unsupported\.
-\- Plugin class 'androidx\.build\.AndroidXImplPlugin': read system property 'user\.dir'
-See https://docs\.gradle\.org/[0-9]+\.[0-9]+.*/userguide/configuration_cache\.html\#config_cache:requirements:undeclared_sys_prop_read
 See https://docs\.gradle\.org/[0-9]+\.[0-9]+.*/userguide/configuration_cache\.html\#config_cache:requirements:use_project_during_execution
 # https://youtrack.jetbrains.com/issue/KT-52694
 \- Task \`:[:A-Za-z0-9#\-]+` of type \`org\.jetbrains\.kotlin\.gradle\.tooling\.BuildKotlinToolingMetadataTask\$FromKotlinExtension\`\: invocation of \'Task\.project\' at execution time is unsupported\.
 \- Task `[^ ]*validateProperties` of type `[^ ]*ValidatePropertiesTask`: invocation of 'Task\.project' at execution time is unsupported\.
-See https://docs\.gradle\.org/[0-9]+\.[0-9]+.*/userguide/configuration_cache\.html\#config_cache:requirements:task_access
 plus [0-9]+ more problems\. Please see the report for details\.
 See the complete report at file://\$SUPPORT/build/reports/configuration\-cache/[^/]*/[^/]*/configuration\-cache\-report\.html
 See the complete report at file://\$OUT_DIR/androidx/build/reports/configuration\-cache/[^ ]*/[^ ]*/configuration\-cache\-report\.html
-# > Task :annotation:annotation-experimental-lint:test
-WARNING: An illegal reflective access operation has occurred
-WARNING: Illegal reflective access by org\.robolectric\.interceptors\.AndroidInterceptors\$FileDescriptorInterceptor to field java\.io\.FileDescriptor\.fd
-WARNING: Please consider reporting this to the maintainers of org\.robolectric\.interceptors\.AndroidInterceptors\$FileDescriptorInterceptor
-WARNING: Illegal reflective access by org\.robolectric\.util\.ReflectionHelpers\$[0-9]+ \(file:\$CHECKOUT/prebuilts/androidx/external/org/robolectric/shadowapi/[0-9]+\.[0-9]+\.[0-9]+/shadowapi\-[0-9]+\.[0-9]+\.[0-9]+\.jar\) to field java\.io\.FileDescriptor\.fd
-WARNING: Please consider reporting this to the maintainers of org\.robolectric\.util\.ReflectionHelpers\$[0-9]+
-WARNING: Please consider reporting this to the maintainers of org\.jetbrains\.kotlin\.kapt[0-9]+\.base\.javac\.KaptJavaFileManager
-WARNING: Illegal reflective access by com\.intellij\.util\.ReflectionUtil \(file:\$CHECKOUT/prebuilts/androidx/external/com/google/devsite/dackka/[0-9]+\.[0-9]+\.[0-9]+/dackka\-[0-9]+\.[0-9]+\.[0-9]+\.jar\) to method java\.util\.ResourceBundle\.setParent\(java\.util\.ResourceBundle\)
-WARNING: Please consider reporting this to the maintainers of com\.intellij\.util\.ReflectionUtil
-WARNING: Use \-\-illegal\-access=warn to enable warnings of further illegal reflective access operations
-WARNING: All illegal access operations will be denied in a future release
-androidx\.room\.processor\.AutoMigrationProcessorTest > testClassImplementsAutoMigrationSpec PASSED
-androidx\.room\.ext\.ElementExtTest > methodsInClass\[preCompile_false\] PASSED
-androidx\.room\.processor\.AutoMigrationProcessorTest > testElementIsClass PASSED
-androidx\.room\.ext\.ElementExtTest > primitiveTypes\[preCompile_false\] PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > invalidConverterType PASSED
-androidx\.room\.processor\.AutoMigrationProcessorTest > testInnerClassMustBeStatic PASSED
-androidx\.room\.ext\.ElementExtTest > methodsInInterface\[preCompile_false\] PASSED
-androidx\.room\.processor\.AutoMigrationProcessorTest > testElementHasNoArgConstructor PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > validCase PASSED
-androidx\.room\.ext\.ElementExtTest > types\[preCompile_false\] PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > checkDuplicates PASSED
-androidx\.room\.ext\.ElementExtTest > methodsInClass\[preCompile_true\] PASSED
-androidx\.room\.ext\.ElementExtTest > primitiveTypes\[preCompile_true\] PASSED
-androidx\.room\.ext\.ElementExtTest > methodsInInterface\[preCompile_true\] PASSED
-androidx\.room\.ext\.ElementExtTest > types\[preCompile_true\] PASSED
-androidx\.room\.parser\.SQLTypeAffinityTest > affinityTypes PASSED
-androidx\.room\.processor\.DaoProcessorTest > jvmNameOnDao\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > checkDuplicates_nullability PASSED
-androidx\.room\.processor\.BaseDaoTest > delete PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > parametrizedTypeUnbound PASSED
-androidx\.room\.processor\.BaseDaoTest > insert PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > testNoConverters PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > checkPublic PASSED
-androidx\.room\.processor\.DaoProcessorTest > query_dontWarnIfTransactionNotIsMissingForRelation\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.BaseDaoTest > deleteArray PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > checkNoArgConstructor PASSED
-androidx\.room\.processor\.DaoProcessorTest > suppressedWarnings\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.BaseDaoTest > updateVarArg PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > parametrizedTypeSpecific PASSED
-androidx\.room\.processor\.DaoProcessorTest > testWithInsertAndQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > primitiveBoth PASSED
-androidx\.room\.processor\.BaseDaoTest > update PASSED
-androidx\.room\.processor\.DaoProcessorTest > testBothAnnotations\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > primitiveFrom PASSED
-androidx\.room\.processor\.BaseDaoTest > deleteVarArg PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > parametrizedTypeBoundViaParent PASSED
-androidx\.room\.processor\.DaoProcessorTest > query_warnIfTransactionIsMissingForRelation\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > checkNoArgConstructor_withStatic PASSED
-androidx\.room\.processor\.BaseDaoTest > updateArray PASSED
-androidx\.room\.processor\.DaoProcessorTest > testDeleteQueryWithVoidReturn\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > nonNullButNotBoxed PASSED
-androidx\.room\.processor\.DaoProcessorTest > testNonAbstract\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.BaseDaoTest > updateList PASSED
-androidx\.room\.processor\.CustomConverterProcessorTest > primitiveTo PASSED
-androidx\.room\.processor\.DaoProcessorTest > testUnusedEnumCompilesWithoutError\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.DatabaseViewProcessorTest > arguments PASSED
-androidx\.room\.processor\.BaseDaoTest > insertArray PASSED
-androidx\.room\.processor\.DaoProcessorTest > skipQueryVerification\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.BaseDaoTest > insertVarArg PASSED
-androidx\.room\.processor\.DatabaseViewProcessorTest > referenceOtherView PASSED
-androidx\.room\.processor\.BaseDaoTest > insertList PASSED
-androidx\.room\.processor\.DatabaseViewProcessorTest > emptyQuery PASSED
-androidx\.room\.processor\.DaoProcessorTest > suppressedWarningsKotlin\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.DatabaseViewProcessorTest > missingAnnotation PASSED
-androidx\.room\.processor\.DaoProcessorTest > testAbstractClass\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.DatabaseViewProcessorTest > basic PASSED
-androidx\.room\.processor\.DatabaseViewProcessorTest > nonSelect PASSED
-androidx\.room\.processor\.DaoProcessorTest > query_dontWarnIfTransactionIsMissingForRelation_suppressed\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.DatabaseViewProcessorTest > viewName_sqlite PASSED
-androidx\.room\.processor\.DaoProcessorTest > testSelectQueryWithVoidReturn\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.DatabaseViewProcessorTest > viewName PASSED
-androidx\.room\.processor\.FieldProcessorTest > nameVariations_underscore PASSED
-androidx\.room\.processor\.DaoProcessorTest > testInterface\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.FieldProcessorTest > columnName PASSED
-androidx\.room\.processor\.DaoProcessorTest > testAbstractMethodWithoutQueryInLibraryClass\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.FieldProcessorTest > unboundGeneric PASSED
-androidx\.room\.processor\.DaoProcessorTest > suppressedWarningsInheritance\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.BaseDaoTest > extendSameInterfaceTwice PASSED
-androidx\.room\.processor\.DaoProcessorTest > testAbstractMethodWithoutQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.BaseDaoTest > deleteList PASSED
-androidx\.room\.processor\.DaoProcessorTest > jvmNameOnDao\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DaoProcessorTest > query_dontWarnIfTransactionNotIsMissingForRelation\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > resolveDatabaseViews_circular PASSED
-androidx\.room\.processor\.DaoProcessorTest > suppressedWarnings\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > foreignKey_goodWithPrimaryKey PASSED
-androidx\.room\.processor\.DaoProcessorTest > testWithInsertAndQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DaoProcessorTest > testBothAnnotations\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DaoProcessorTest > query_warnIfTransactionIsMissingForRelation\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > foreignKey_goodWithIndex PASSED
-androidx\.room\.processor\.DaoProcessorTest > testDeleteQueryWithVoidReturn\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > detectMissingDaoAnnotationInLibraryClass PASSED
-androidx\.room\.processor\.FieldProcessorTest > primitiveArray PASSED
-androidx\.room\.processor\.DaoProcessorTest > testNonAbstract\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.FieldProcessorTest > nameVariations_is PASSED
-androidx\.room\.processor\.DaoProcessorTest > testUnusedEnumCompilesWithoutError\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > suppressedWarnings PASSED
-androidx\.room\.processor\.DaoProcessorTest > skipQueryVerification\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > nonDeclaredEntity PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > daoConstructor_wrongDatabase PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > view_duplicateNamesWithEntity PASSED
-androidx\.room\.processor\.DaoProcessorTest > suppressedWarningsKotlin\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DaoProcessorTest > testAbstractClass\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DaoProcessorTest > query_dontWarnIfTransactionIsMissingForRelation_suppressed\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > twoDaoMethodsForTheSameDao PASSED
-androidx\.room\.processor\.DaoProcessorTest > testSelectQueryWithVoidReturn\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > foreignKey_missingParentColumn PASSED
-androidx\.room\.processor\.FieldProcessorTest > primitives PASSED
-androidx\.room\.processor\.DaoProcessorTest > testInterface\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > simple PASSED
-androidx\.room\.processor\.FieldProcessorTest > byteArrayWithEnforcedType PASSED
-androidx\.room\.processor\.DaoProcessorTest > testAbstractMethodWithoutQueryInLibraryClass\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.FieldProcessorTest > emptyColumnName PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > view_circularReference PASSED
-androidx\.room\.processor\.FieldProcessorTest > nameVariations_m PASSED
-androidx\.room\.processor\.DaoProcessorTest > suppressedWarningsInheritance\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > detectMissingExternalContentEntity PASSED
-androidx\.room\.processor\.DaoProcessorTest > testAbstractMethodWithoutQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > detectMissingBaseClass PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > autoMigrationDefinedButDatabaseSchemaExportOff PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > customCollection PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > resolveDatabaseViews_empty PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > notAnEntity PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > cache_pojo PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > daoConstructor_specificDatabase PASSED
-androidx\.room\.processor\.FieldProcessorTest > defaultValues_number PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > duplicateIndexNames PASSED
-androidx\.room\.processor\.FieldProcessorTest > generic PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > differentSchemaResolver PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > autoMigrationEmptySchemaFiles PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > daoConstructor_multipleDatabases_RoomDatabase PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > foreignKey_missingParentIndex PASSED
-androidx\.room\.processor\.FieldProcessorTest > boxed PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > multiple PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > invalidReturnType PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > detectMissingEntityAnnotationInLibraryClass PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > targetEntity_notDeclared PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > daoConstructor_multipleDatabases_specificDatabases PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > targetEntity PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > foreignKey_missingParent PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > single PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > targetEntityExtraColumn PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > daoConstructor_multipleDatabases_empty PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > autoMigrationToSchemaNotFound PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > set PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > resolveDatabaseViews_nested PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > two PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > daoMethod_nonDeclaredReturnType PASSED
-androidx\.room\.processor\.FieldProcessorTest > boxedArray PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > daoConstructor_multipleDatabases_noMatch PASSED
-androidx\.room\.processor\.FieldProcessorTest > defaultValues_nonNull PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > jvmNameOnDaoMethod PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > allAutoMigrationSchemasProvidedButNotRoomGenerated PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > daoConstructor_RoomDatabase PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > insertNotAReferencedEntity PASSED
-androidx\.room\.processor\.FieldProcessorTest > defaultValues_text PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > autoMigrationSchemasNotFound PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > cache_entity PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > skipBadQueryVerification PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > list PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > detectDuplicateTableNames PASSED
-androidx\.room\.processor\.FieldProcessorTest > collate PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > view_duplicateNames PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > array PASSED
-androidx\.room\.processor\.FieldProcessorTest > nameVariations_has PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > autoMigrationFromSchemaNotFound PASSED
-androidx\.room\.processor\.FieldProcessorTest > nameVariations PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > targetEntitySameAsPojo PASSED
-androidx\.room\.processor\.FieldProcessorTest > indexed PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > noParams PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > multipleDatabases PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > targetEntityWithRelation PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > insertIterable PASSED
-androidx\.room\.processor\.DatabaseProcessorTest > detectMissingTable PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > targetEntitySingle PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > iterable PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(x, getX, setX\)\] PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(x, getX, x\)\] PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(x, x, setX\)\] PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(x, x, x\)\] PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(_x, getX, setX\)\] PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(_x, getX, x\)\] PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(_x, x, setX\)\] PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(_x, x, x\)\] PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > onConflict_EachValue PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(mX, getX, setX\)\] PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(mX, getX, x\)\] PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(mX, x, setX\)\] PASSED
-androidx\.room\.processor\.EntityNameMatchingVariationsTest > testSuccessfulParamToMethodMatching\[\(mX, x, x\)\] PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > nonDefaultTokenizer PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > notAllowedIndex PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > invalidReturnType PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > primaryKeyInEntityAnnotation PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > readNoParams PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > missingPrimaryKeyAnnotation PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > missingNotIndexedField PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > insertDifferentTypes PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > badExternalContentEntity_missingFields PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > customTokenizer PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > badPrimaryKeyName PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > badPrimaryKeyAffinity PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > mismatchedReturnType[0-9]+ PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > omittedRowId PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > badPrefixValue_negative PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > missingLanguageIdField PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > simple PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > badExternalContentEntity_notAnEntity PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > badLanguageIdAffinity PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > insertSet PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > multiplePrimaryKeysInEntityAnnotation PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > insertTwo PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > multiplePrimaryKeyAnnotations PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > targetEntityExtraColumn PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > suspendReturnsDeferredType PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > notAllowedForeignKeys PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > targetEntity_emptyClassParameter PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > badPrefixValue_zero PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > insertArray PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > missingEntityAnnotation PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > insertQueue PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_nestedRelation PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > targetEntityMissingPrimaryKey PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_missingParent PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_empty PASSED
-androidx\.room\.processor\.PojoProcessorTest > noGetter_scopeReadCursor PASSED
-androidx\.room\.processor\.PojoProcessorTest > transient_withColumnInfo PASSED
-androidx\.room\.processor\.PojoProcessorTest > transient_insideEmbedded PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > mismatchedReturnType PASSED
-androidx\.room\.processor\.PojoProcessorTest > inheritedPrivate PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > targetEntitySameAsPojo PASSED
-androidx\.room\.processor\.PojoProcessorTest > nestedEmbedded PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > targetEntityWithRelation PASSED
-androidx\.room\.processor\.PojoProcessorTest > ignoredColumns_noSetterGetter PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > targetEntityColumnDefaultValue PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_associateBy_missingEntityColumn PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > insertSingle PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_stringList PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > differentTypes PASSED
-androidx\.room\.processor\.PojoProcessorTest > ignoredColumns_noConstructor PASSED
-androidx\.room\.processor\.PojoProcessorTest > duplicateColumnNamesFromEmbedded PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > targetEntityExtraColumnIgnored PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_associateBy_defaultColumns PASSED
-androidx\.room\.processor\.DeletionMethodProcessorTest > targetEntityWithEmbedded PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_associateBy_missingParentColumn PASSED
-androidx\.room\.processor\.PojoProcessorTest > duplicateColumnNames PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_relationParameter PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_simple PASSED
-androidx\.room\.processor\.PojoProcessorTest > recursion_[0-9]+Level_relation PASSED
-androidx\.room\.processor\.PojoProcessorTest > ignoredColumns_columnInfo PASSED
-androidx\.room\.processor\.PojoProcessorTest > noGetter_scopeTwoWay PASSED
-androidx\.room\.processor\.Fts[0-9]+TableEntityProcessorTest > multiplePrimaryKeys PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_nestedField PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > invalidAnnotationInStaticMethod PASSED
-androidx\.room\.processor\.PojoProcessorTest > dataClass_withJvmOverloads_primaryConstructor PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > invalidAnnotationInMethod PASSED
-androidx\.room\.processor\.PojoProcessorTest > embedded_badType PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > invalidAnnotationInAutoValueMethod PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_multipleMatching PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > validAnnotationInAutoValueParentMethod PASSED
-androidx\.room\.processor\.PojoProcessorTest > recursion_[0-9]+Level_relationToEmbed PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_dontTryForBindToScope PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > validEmbeddedAnnotationInAutoValueAbstractMethod PASSED
-androidx\.room\.processor\.PojoProcessorTest > ignoredColumns_missing PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > validAnnotationInField PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_withNullabilityAnnotation PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > validAnnotationInAutoValueAbstractMethod PASSED
-androidx\.room\.processor\.PojoProcessorTest > embedded_generic PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > invalidAnnotationInAutoValueParentMethod PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > validReturnTypes PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_affinityMismatch PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > validRelationAnnotationInAutoValueAbstractMethod PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > targetEntityMissingRequiredColumn PASSED
-androidx\.room\.processor\.PojoProcessorTest > recursion_[0-9]+Levels PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > validAnnotationInStaticField PASSED
-androidx\.room\.processor\.PojoProcessorTest > recursion_[0-9]+Levels_relationToEmbed PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > invalidAnnotationInAbstractMethod PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > insertList PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_notEntity PASSED
-androidx\.room\.processor\.PojoProcessorTargetMethodTest > validAnnotationInAutoValueImplementedInterfaceMethod PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > onConflict_Default PASSED
-androidx\.room\.processor\.PojoProcessorTest > noSetter_scopeTwoWay PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > insertNotAnEntity PASSED
-androidx\.room\.processor\.PojoProcessorTest > ignoredColumns PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testDoesNotImplementEqualsAndHashcodeQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > transient_relation PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > targetEntityAutoGeneratedPrimaryKey PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testVoidInsertQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_extendsBounds PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testParamBindingTwoBindVarsIntoTheSameParameter\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > recursion_[0-9]+Levels_onlyEmbeds_onlyPojos PASSED
-androidx\.room\.processor\.PojoProcessorTest > recursion_[0-9]+Level_relation_specifyEntity PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testLiveDataWithWithClauseAndNothingToObserve\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > recursion_[0-9]+Level_embedded PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_missingEntityField PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > skipVerification\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_associateBy_warnIndexOnJunctionColumn PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > relationWithExtendsBounds\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > cache PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUnusedParameters\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_associateBy_withView PASSED
-androidx\.room\.processor\.PojoProcessorTest > recursion_[0-9]+Levels_onlyEmbeds_pojoToEntity PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testLiveDataQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > recursion_branchAtLevel[0-9]+_afterBackTrack PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_tooManyColumns\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_multipleMatching_withNoArg PASSED
-androidx\.room\.processor\.PojoProcessorTest > embedded_nullability PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testInvalidLinkedListCollectionInMultimapJoin\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_associateBy PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_view PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_missingNonNull\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > dropSubPrimaryKeyNoWarningForPojo PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoOneToManyLong\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testLiveDataWithNothingToObserve\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testNameWithUnderscore\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > dataClass_primaryConstructor PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testOneToOneStringMapInfoForKeyInsteadOfColumn\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_multipleMatchingWithIgnored PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testLongInsertQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_primitiveList PASSED
-androidx\.room\.processor\.PojoProcessorTest > embedded PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testAmbiguousColumnInMapInfo\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_noMatchBadType PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testAmbiguousColumnInMapPojo\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_badReturnTypeInGetter PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_badQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > noSetter_scopeBindStmt PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneLong\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > embeddedWithPrefix PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testSimpleDelete\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_associateBy_missingSpecifiedEntityColumn PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > suspendReturnsDeferredType PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_notCollection PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUseMapInfoWithBothEmptyColumnsProvided\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_ambiguous_twoFields PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > insertCustomCollection PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUseMapInfoWithColumnAlias\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > transient_embedded PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > onConflict_Invalid PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_badProjection PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > skipVerificationPojo\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > targetEntityTwo PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_associateBy_missingSpecifiedParentColumn PASSED
-androidx\.room\.processor\.PojoProcessorTest > transient_ignore PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > targetEntityExtraColumnIgnored PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_tooManyFields\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > recursion_[0-9]+Level_[0-9]+LevelDown PASSED
-androidx\.room\.processor\.InsertionMethodProcessorTest > targetEntityWithEmbedded PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_nonJavaName\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_bindForTwoWay PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > joinAndAbandonEntity PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_notDeclared PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadReceiveChannelReturnForQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_ambiguous_twoFieldsExactMatch PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > additional PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testVarArgs\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > summary PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMultiTableDataSourceFactoryQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > additional_immediateValue PASSED
-androidx\.room\.processor\.PojoProcessorTest > setterStartsWithIs PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_noMatchingFields\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > noGetter_scopeBindStmt PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > embedPojo PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_ambiguous_oneTypeMatches PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUseMapInfoWithOriginalTableAndColumnName\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > joinSelf PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_noMatchMultiArg PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testReadDeleteWithBadReturnType\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > noSetter_scopeReadFromCursor PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > withTableNameAndAlias PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_missingType PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testReadNoParams\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > ignore PASSED
-androidx\.room\.processor\.PojoProcessorTest > relation_columnInfo PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > withTableName PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadChannelReturnForQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.PojoProcessorTest > constructor_noMatch PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > newlineInProjection PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > badType_nullable PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBoundGeneric\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > aliasWithInnerJoin PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > testMissingMapInfoOneToManyLong PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_expandProjection\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > specifyAlias PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > tooManyArgs PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > specifyTable PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > testOneToOneStringMapInfoForKeyInsteadOfColumn PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoOneToManyString\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > noArgs PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > join PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > query_detectTransaction_selectInTransaction\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > observableWithoutEntities_positionalDataSource PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > selectConstant PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testInsertQueryWithBadReturnType\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > stringRawQuery PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > irrelevantAlias PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneLong PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testDataSourceFactoryQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > additional_logic PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > testUseMapInfoWithBothEmptyColumnsProvided PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > embedded PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_exactMatch\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > positionalDataSource PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > extraColumn PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUseMapInfoWithColumnsNotInQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > observableWithoutEntities_dataSourceFactory PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > joinWithoutPrefix PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > badType PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUseMapInfoWithTableAndColumnName\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > selectParameter PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > observed_embedded PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneTypeConverterValue\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > noNeedToExpand PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > testDoesNotImplementEqualsAndHashcodeRawQuery PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadSendChannelReturnForQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > additional_innerQuery PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > supportRawQuery PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > parameter PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_dontRemoveUnusedColumnsWhenColumnNamesConflict\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > observed_notAnEntity PASSED
-androidx\.room\.processor\.ProjectionExpanderTest > joinAndAbandon PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > primitive_removeUnusedColumns\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > pojo PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_renamedColumn\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > void PASSED
-androidx\.room\.processor\.RemoveUnusedColumnsTest > expandProjection_annotateMethod PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > suppressWarnings\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > testMissingMapInfoOneToManyString PASSED
-androidx\.room\.processor\.RemoveUnusedColumnsTest > annotateDb PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > varargs PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneString\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > observableWithoutEntities PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneTypeConverterKey\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RemoveUnusedColumnsTest > annotateDao PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > observed_relationPojo PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testVoidDeleteQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RemoveUnusedColumnsTest > expandProjection_annotateDb PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneTypeConverterValue PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testLiveDataWithWithClause\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > suspendUnit PASSED
-androidx\.room\.processor\.RemoveUnusedColumnsTest > expandProjection_annotateDao PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneString PASSED
-androidx\.room\.processor\.RemoveUnusedColumnsTest > annotateMethod PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneTypeConverterKey PASSED
-androidx\.room\.processor\.RemoveUnusedColumnsTest > noAnnotationGivesWarning PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > targetEntityMissingPrimaryKey PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > badConflict PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > goodConflict PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > customCollection PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > notAnEntity PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > invalidReturnType PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > targetEntity_notDeclared PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > targetEntity PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > single PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > targetEntityExtraColumn PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > suspendReturnsDeferredType\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > set PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testInvalidGenericMultimapJoin\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > two PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBoundGenericParameter\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > suspendReturnsDeferredType PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_exactMatchWithStar\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > withObservedEntities PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoOneToOneLong\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > testMissingMapInfoOneToOneLong PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_removeUnusedColumns\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.RawQueryMethodProcessorTest > testMissingMapInfoOneToOneString PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > test[0-9]+MissingParameterForBinding\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.TransactionMethodProcessorTest > deferredReturnType_liveData PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_multimapQuery_removeUnusedColumns\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.TransactionMethodProcessorTest > deferredReturnType_computableLiveData PASSED
-androidx\.room\.processor\.TransactionMethodProcessorTest > deferredReturnType_rx[0-9]+_flowable PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadReturnForDeleteQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testGenericReturnType\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.TransactionMethodProcessorTest > simple PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > query_detectTransaction_select\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.TransactionMethodProcessorTest > deferredReturnType_rx[0-9]+_single PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testVoidUpdateQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.TransactionMethodProcessorTest > deferredReturnType_flow PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > list PASSED
-androidx\.room\.processor\.TransactionMethodProcessorTest > modifier_final PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoOneToOneString\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > array PASSED
-androidx\.room\.processor\.TransactionMethodProcessorTest > modifier_private PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testSingleParam\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.TransactionMethodProcessorTest > deferredReturnType_publisher PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > targetEntitySameAsPojo PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadReturnForUpdateQuery\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > noParams PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingParameterForBinding\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.TransactionMethodProcessorTest > deferredReturnType_listenableFuture PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > targetEntityWithRelation PASSED
-androidx\.room\.processor\.TransactionMethodProcessorTest > deferredReturnType_rx[0-9]+_completable PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_tooManyFieldsAndColumns\[enableDbVerification=true\] PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > iterable PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testParamBindingMatchingSimpleBind\[enableDbVerification=true\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readBoxed\[kind:int,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > bind\[kind:int,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testParamBindingMatchingNoName\[enableDbVerification=true\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > read\[kind:int,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testDoesNotImplementEqualsAndHashcodeQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readNullable\[kind:int,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testVoidInsertQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > boxedBind\[kind:int,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > nullableBind\[kind:int,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testParamBindingTwoBindVarsIntoTheSameParameter\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testLiveDataWithWithClauseAndNothingToObserve\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readBoxed\[kind:byte,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(byte\) crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > bind\[kind:byte,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(byte\) crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > skipVerification\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > relationWithExtendsBounds\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > read\[kind:byte,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(byte\) crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUnusedParameters\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readNullable\[kind:byte,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(byte\) crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testLiveDataQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > boxedBind\[kind:byte,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(byte\) crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_tooManyColumns\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > nullableBind\[kind:byte,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(byte\) crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testInvalidLinkedListCollectionInMultimapJoin\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readBoxed\[kind:short,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > bind\[kind:short,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > read\[kind:short,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_missingNonNull\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readNullable\[kind:short,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoOneToManyLong\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testLiveDataWithNothingToObserve\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > boxedBind\[kind:short,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testNameWithUnderscore\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > nullableBind\[kind:short,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getShort\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testOneToOneStringMapInfoForKeyInsteadOfColumn\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readBoxed\[kind:long,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getLong\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testLongInsertQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testAmbiguousColumnInMapInfo\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testAmbiguousColumnInMapPojo\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > bind\[kind:long,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getLong\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > read\[kind:long,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getLong\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_badQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readNullable\[kind:long,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getLong\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneLong\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > boxedBind\[kind:long,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getLong\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testSimpleDelete\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUseMapInfoWithBothEmptyColumnsProvided\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUseMapInfoWithColumnAlias\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > nullableBind\[kind:long,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = crs\.getLong\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > skipVerificationPojo\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readBoxed\[kind:char,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(char\) crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > suspendReturnsDeferredType PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_tooManyFields\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > bind\[kind:char,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(char\) crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > targetEntity_emptyClassParameter PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_nonJavaName\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > read\[kind:char,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(char\) crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadReceiveChannelReturnForQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readNullable\[kind:char,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(char\) crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testVarArgs\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > boxedBind\[kind:char,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(char\) crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > nullableBind\[kind:char,bind:_st\.bindLong\([0-9]+, inp\);,cursor:_out = \(char\) crs\.getInt\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMultiTableDataSourceFactoryQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readBoxed\[kind:float,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getFloat\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_noMatchingFields\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUseMapInfoWithOriginalTableAndColumnName\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > bind\[kind:float,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getFloat\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testReadDeleteWithBadReturnType\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > read\[kind:float,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getFloat\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testReadNoParams\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readNullable\[kind:float,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getFloat\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadChannelReturnForQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > boxedBind\[kind:float,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getFloat\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBoundGeneric\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_expandProjection\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > nullableBind\[kind:float,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getFloat\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoOneToManyString\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readBoxed\[kind:double,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getDouble\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > query_detectTransaction_selectInTransaction\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > bind\[kind:double,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getDouble\([0-9]+\);\] PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > differentTypes PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testInsertQueryWithBadReturnType\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > read\[kind:double,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getDouble\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testDataSourceFactoryQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > targetEntityExtraColumnIgnored PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readNullable\[kind:double,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getDouble\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > boxedBind\[kind:double,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getDouble\([0-9]+\);\] PASSED
-androidx\.room\.processor\.UpdateMethodProcessorTest > targetEntityWithEmbedded PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_exactMatch\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUseMapInfoWithColumnsNotInQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testUseMapInfoWithTableAndColumnName\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > nullableBind\[kind:double,bind:_st\.bindDouble\([0-9]+, inp\);,cursor:_out = crs\.getDouble\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneTypeConverterValue\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readBoxed\[kind:java\.lang\.String,bind:_st\.bindString\([0-9]+, inp\);,cursor:_out = crs\.getString\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadSendChannelReturnForQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_dontRemoveUnusedColumnsWhenColumnNamesConflict\[enableDbVerification=false\] SKIPPED
-androidx\.room\.processor\.QueryMethodProcessorTest > primitive_removeUnusedColumns\[enableDbVerification=false\] SKIPPED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > bind\[kind:java\.lang\.String,bind:_st\.bindString\([0-9]+, inp\);,cursor:_out = crs\.getString\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_renamedColumn\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > read\[kind:java\.lang\.String,bind:_st\.bindString\([0-9]+, inp\);,cursor:_out = crs\.getString\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > suppressWarnings\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readNullable\[kind:java\.lang\.String,bind:_st\.bindString\([0-9]+, inp\);,cursor:_out = crs\.getString\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneString\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > boxedBind\[kind:java\.lang\.String,bind:_st\.bindString\([0-9]+, inp\);,cursor:_out = crs\.getString\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BuiltInConverterFlagsTest > all_undefined PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoImmutableListMultimapOneToOneTypeConverterKey\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > nullableBind\[kind:java\.lang\.String,bind:_st\.bindString\([0-9]+, inp\);,cursor:_out = crs\.getString\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testVoidDeleteQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readBoxed\[kind:byte\[\],bind:_st\.bindBlob\([0-9]+, inp\);,cursor:_out = crs\.getBlob\([0-9]+\);\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testLiveDataWithWithClause\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > bind\[kind:byte\[\],bind:_st\.bindBlob\([0-9]+, inp\);,cursor:_out = crs\.getBlob\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > read\[kind:byte\[\],bind:_st\.bindBlob\([0-9]+, inp\);,cursor:_out = crs\.getBlob\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > readNullable\[kind:byte\[\],bind:_st\.bindBlob\([0-9]+, inp\);,cursor:_out = crs\.getBlob\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BuiltInConverterFlagsTest > all_disabledInDb_disabledInDao_enabledInEntity PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > boxedBind\[kind:byte\[\],bind:_st\.bindBlob\([0-9]+, inp\);,cursor:_out = crs\.getBlob\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BasicColumnTypeAdaptersTest > nullableBind\[kind:byte\[\],bind:_st\.bindBlob\([0-9]+, inp\);,cursor:_out = crs\.getBlob\([0-9]+\);\] PASSED
-androidx\.room\.solver\.BuiltInConverterFlagsTest > all_disabledInEntity PASSED
-androidx\.room\.solver\.BuiltInConverterFlagsTest > enums_disabledInDb PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > warnIfTurnedOffInKsp PASSED
-androidx\.room\.solver\.BuiltInConverterFlagsTest > uuid_disabledInDb PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > dontAssumeTypesCanBeConvertedUserCase PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > withOnlyNullableConverters_cursor PASSED
-androidx\.room\.solver\.BuiltInConverterFlagsTest > all_disabledInDb_enabledInDao_enabledInEntity PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > pojoProcess PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testMissingRx[0-9]+Room PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findPagingSourceIntKey PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > withOnlyNullableConverters PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindDeleteOrUpdateListenableFuture PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testJavaUtilUUIDCompilesWithoutError PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > dontAssumeUserTypesCanBeConvertedIntoEachOther PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testOneWayConversion PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findRx[0-9]+PagingSourceKotlinCollectionValue PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindLiveData PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindDeleteOrUpdateCompletable PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > withNonNullAndNullableReceiving_cursor PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findPagingSourceJavaCollectionValue PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > checkSyntheticConverters PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindInsertListenableFuture PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testEqualsAndHashcodeImplemented PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testDate PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > suspendReturnsDeferredType\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > withFullyNullableConverters_cursor PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testVia[0-9]+TypeAdapters PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testInvalidGenericMultimapJoin\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBoundGenericParameter\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindFlowable PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > knownColumnTypeToExplicitType PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_exactMatchWithStar\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findListenableFuturePagingSourceJavaCollectionValue PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoOneToOneLong\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_removeUnusedColumns\[enableDbVerification=false\] SKIPPED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindInsertCompletable PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > test[0-9]+MissingParameterForBinding\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_multimapQuery_removeUnusedColumns\[enableDbVerification=false\] SKIPPED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > withNonNullableConverters_cursor PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findQueryParameterAdapter_collections PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadReturnForDeleteQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findPagingSourceStringKey PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testGenericReturnType\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > query_detectTransaction_select\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindPublisher PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > withFullyNullableConverters PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testVoidUpdateQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingMapInfoOneToOneString\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testEqualsAndHashcodeCheckWithKotlinPrimitive PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testSingleParam\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > withNonNullAndNullableReceiving PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testMissingRoomPaging PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testBadReturnForUpdateQuery\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findPagingSourceKotlinCollectionValue PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testMissingParameterForBinding\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testListenableFuturePagingSourceBinder PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > pojo_tooManyFieldsAndColumns\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.NullabilityAwareTypeConverterStoreTest > withNonNullableConverters PASSED
-androidx\.room\.solver\.TypeConverterCostTest > sum PASSED
-androidx\.room\.solver\.TypeConverterCostTest > sum[0-9]+ PASSED
-androidx\.room\.solver\.TypeConverterCostTest > sections PASSED
-androidx\.room\.solver\.TypeConverterCostTest > compare PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testJavaLangEnumCompilesWithoutError PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testParamBindingMatchingSimpleBind\[enableDbVerification=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindInsertSingle PASSED
-androidx\.room\.processor\.QueryMethodProcessorTest > testParamBindingMatchingNoName\[enableDbVerification=false\] PASSED
-androidx\.room\.testing\.InProcessorTest > testInProcessorTestRuns\[kotlinCode_true\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindDeleteOrUpdateMaybe PASSED
-androidx\.room\.testing\.InProcessorTest > testInProcessorTestRuns\[kotlinCode_false\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_dontDuplicationChildIndex_SingleColumn PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > getterWithBadType PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testFullEntityQuery\[useLocalizedCollation=true\] PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testFlattenQuery\[useLocalizedCollation=true\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_simple PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testViewNoSuchColumn\[useLocalizedCollation=true\] PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testDeleteQuery\[useLocalizedCollation=true\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_sort_desc PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testBadQuery\[useLocalizedCollation=true\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_multiple PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > typeAliases PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testPartialFields\[useLocalizedCollation=true\] PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testUpdateQuery\[useLocalizedCollation=true\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findRx[0-9]+PagingSourceJavaCollectionValue PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_warnMissingChildrenIndex PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testCollateBasQuery\[useLocalizedCollation=true\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findPagingSourceKotlinMutableSetValue PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_nullableEmbeddedObject PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testResultWithArgs\[useLocalizedCollation=true\] PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testFullViewQuery\[useLocalizedCollation=true\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_fromField PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testPagingSourceBinder PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testGrouped\[useLocalizedCollation=true\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > relationInEntity PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testColumnSubquery\[useLocalizedCollation=true\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testRx[0-9]+PagingSourceBinder PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > tooManyGetters PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testCollate\[useLocalizedCollation=true\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findDataSource PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > defaultValue_exprError\[useLocalizedCollation=true\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > missingColumnAdapter PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testEqualsAndHashcodeCheckWithJavaPrimitive PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testConcat\[useLocalizedCollation=true\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > customName PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testRenamedField\[useLocalizedCollation=true\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testMissingRoomPagingGuava PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testVia[0-9]+TypeAdapter PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testSimpleDatabase\[useLocalizedCollation=true\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_NonNull PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testFullEntityQuery\[useLocalizedCollation=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testMissingRoomPagingRx[0-9]+ PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testFlattenQuery\[useLocalizedCollation=false\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_keptGrandParentEntityIndex PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testViewNoSuchColumn\[useLocalizedCollation=false\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_dontIndexIfAlreadyPrimaryKey PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testInvalidNonStaticInnerClass PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testDeleteQuery\[useLocalizedCollation=false\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > recursion_[0-9]+Level PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testBadQuery\[useLocalizedCollation=false\] PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testPartialFields\[useLocalizedCollation=false\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > okTableName PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testUpdateQuery\[useLocalizedCollation=false\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_embedded PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testCollateBasQuery\[useLocalizedCollation=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindInsertMaybe PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testResultWithArgs\[useLocalizedCollation=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testJavaLangBoolean PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_droppedParentEntityIndex PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testFullViewQuery\[useLocalizedCollation=false\] PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testDirect PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testGrouped\[useLocalizedCollation=false\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_multiColumn PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findListenableFutureKotlinCollectionValue PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testColumnSubquery\[useLocalizedCollation=false\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_emptyChildColumns PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findDataSourceFactory PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testCollate\[useLocalizedCollation=false\] PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > defaultValue_exprError\[useLocalizedCollation=false\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > dropSubPrimaryKey PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findPagingSourceJavaListValue PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testConcat\[useLocalizedCollation=false\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_badEntity PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindDeleteOrUpdateSingle PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testRenamedField\[useLocalizedCollation=false\] PASSED
-androidx\.room\.verifier\.DatabaseVerifierTest > testSimpleDatabase\[useLocalizedCollation=false\] PASSED
-androidx\.room\.vo\.FtsEntityTest > createStatement_simpleTokenizer_noTokenizerArgs PASSED
-androidx\.room\.vo\.FtsEntityTest > createStatement_simpleTokenizer_withTokenizerArgs PASSED
-androidx\.room\.vo\.FtsEntityTest > createStatement_nonSimpleTokenizer_withTokenizerArgs PASSED
-androidx\.room\.vo\.FtsEntityTest > createStatement PASSED
-androidx\.room\.vo\.FtsEntityTest > createStatement_nonSimpleTokenizer_noTokenizerArgs PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_overrideViaEmbedded PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testIntList PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_definedInBothWays PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > simple PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > testFindObservable PASSED
-androidx\.room\.writer\.DaoWriterTest > updateDao PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > badTableName PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_warnMissingChildIndex PASSED
-androidx\.room\.solver\.TypeAdapterStoreTest > findPositionalDataSource PASSED
-androidx\.room\.writer\.DaoWriterTest > complexDao_turkishLocale PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_overrideFromParentEntityViaEntity PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_missingColumn PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_nullableEmbedded PASSED
-androidx\.room\.writer\.DaoWriterTest > writerDao PASSED
-androidx\.room\.solver\.TypeConverterStoreTest > multiStepTypeConverters PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_fromParentEntity PASSED
-androidx\.room\.util\.SchemaDifferTest > testColumnAddedWithColumnInfoDefaultValue PASSED
-androidx\.room\.util\.SchemaDifferTest > testForeignKeyFieldChanged PASSED
-androidx\.room\.util\.SchemaDifferTest > testColumnRemoved PASSED
-androidx\.room\.util\.SchemaDifferTest > testColumnRenamed PASSED
-androidx\.room\.util\.SchemaDifferTest > testTableAddedWithColumnInfoDefaultValue PASSED
-androidx\.room\.util\.SchemaDifferTest > testComplexChangeInvolvingIndex PASSED
-androidx\.room\.util\.SchemaDifferTest > testColumnAddedWithNoDefaultValue PASSED
-androidx\.room\.util\.SchemaDifferTest > testPrimaryKeyChanged PASSED
-androidx\.room\.util\.SchemaDifferTest > testTableRenamedWithoutAnnotation PASSED
-androidx\.room\.util\.SchemaDifferTest > testColumnsAddedInOrder PASSED
-androidx\.room\.util\.SchemaDifferTest > testColumnsAddedWithSameName PASSED
-androidx\.room\.util\.SchemaDifferTest > testTableRemovedWithoutAnnotation PASSED
-androidx\.room\.vo\.DatabaseTest > indexLegacyHash PASSED
-androidx\.room\.vo\.IndexTest > createWithSortOrder PASSED
-androidx\.room\.vo\.IndexTest > createSimpleSQL PASSED
-androidx\.room\.vo\.IndexTest > createUnique PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > noGetterInLibraryClass PASSED
-androidx\.room\.writer\.DaoWriterTest > deletionDao PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_columnCountMismatch PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > missingPrimaryKey PASSED
-androidx\.room\.writer\.DefaultsInDaoTest > abstractDao\[jvmDefaultMode=ALL_COMPATIBILITY\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > getterWithAssignableType_[0-9]+ PASSED
-androidx\.room\.writer\.DaoWriterTest > complexDao PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_sort_multiple PASSED
-androidx\.room\.writer\.DefaultsInDaoTest > interfaceDao_suspend\[jvmDefaultMode=ALL_COMPATIBILITY\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > emptyCustomName PASSED
-androidx\.room\.writer\.DatabaseWriterTest > androidx\.room\.writer\.DatabaseWriterTest\$SmallDB\.testCompileAndVerifySources PASSED
-androidx\.room\.writer\.DefaultsInDaoTest > interfaceDao\[jvmDefaultMode=ALL_COMPATIBILITY\] PASSED
-androidx\.room\.writer\.DefaultsInDaoTest > abstractDao\[jvmDefaultMode=ALL_INCOMPATIBLE\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_autoGenerate PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_MultipleNullable PASSED
-androidx\.room\.writer\.DefaultsInDaoTest > interfaceDao_suspend\[jvmDefaultMode=ALL_INCOMPATIBLE\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_dontDuplicationChildIndex_WhenCovered PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_customName PASSED
-androidx\.room\.writer\.DefaultsInDaoTest > interfaceDao\[jvmDefaultMode=ALL_INCOMPATIBLE\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_nullableEmbeddedInherited PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_droppedGrandParentEntityIndex PASSED
-androidx\.room\.writer\.DefaultsInDaoTest > abstractDao\[jvmDefaultMode=DISABLE\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > ignoredFields PASSED
-androidx\.room\.writer\.DatabaseWriterTest > androidx\.room\.writer\.DatabaseWriterTest\$BigDB\.testCompile\[\(maxStatementCount, valuesPerEntity\)=\([0-9]+, [0-9]+\)\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > setterWithAssignableType_[0-9]+ PASSED
-androidx\.room\.writer\.DefaultsInDaoTest > interfaceDao_suspend\[jvmDefaultMode=DISABLE\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > recursion_[0-9]+Levels_embedToRelation PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_droppedEmbeddedFieldIndex PASSED
-androidx\.room\.writer\.DefaultsInDaoTest > interfaceDao\[jvmDefaultMode=DISABLE\] PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_overrideFromParentField PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_fromParentField PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > tooManyGettersWithDifferentVisibility PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > tooManySettersWithIgnore PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_definedAsAttributesNullable PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_integerOverrideEmbedded PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_notAnEntity PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_Nullable PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > noGetter PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > tooManySettersWithDifferentVisibility PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > setterWithAssignableType PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_embeddedInherited PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_keptParentFieldIndex PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > tooManySetters PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_onEmbeddedField PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > typeAlias PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_nullableOverrideEmbedded PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > tooManyGettersWithDifferentTypes PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_dontDuplicationChildIndex_MultipleColumns PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_nonNull_notNeeded PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > noSetter PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_MultipleNullableAndNonNullable PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_singleStringPrimaryKeyOverrideEmbedded PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_simple PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > recursion_[0-9]+Levels_onlyEmbeds_onlyEntities PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_unique PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_invalidAction PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > ignoreDropSubPrimaryKey PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_invalidChildColumn PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_keptParentEntityIndex PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_overrideFromParentEntityViaField PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > tooManyGettersWithIgnore PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > getterWithAssignableType PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_autoGenerateBadType PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_customTableName PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_droppedEmbeddedEntityIndex PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > setterWithBadType PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_nullableOverrideViaEmbedded PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > tooManySettersWithDifferentTypes PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_droppedParentFieldIndex PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_nameConflict PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > badColumnName PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_badColumnName PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > recursion_[0-9]+Levels_onlyEmbeds_entityToPojo PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_referenceEmbeddedField PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > foreignKey_emptyParentColumns PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_empty PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_overrideEmbedded PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > preferPublicOverProtected PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_nullableEmbeddedObject_multipleParents PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_multipleAnnotations PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > primaryKey_definedAsAttributesNonNull PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > index_invalidOrdersSize PASSED
-androidx\.room\.processor\.TableEntityProcessorTest > notNull PASSED
-androidx\.room\.processor\.autovalue\.AutoValuePojoProcessorDelegateTest > goodLibraryPojo PASSED
-androidx\.room\.processor\.autovalue\.AutoValuePojoProcessorDelegateTest > missingCopyAnnotationsWarning PASSED
-androidx\.room\.processor\.autovalue\.AutoValuePojoProcessorDelegateTest > missingCopyAnnotationsWarning_inInheritedMethodFromInterface PASSED
-androidx\.room\.processor\.autovalue\.AutoValuePojoProcessorDelegateTest > missingCopyAnnotationsWarning_inInheritedMethodFromSuper PASSED
-androidx\.room\.processor\.autovalue\.AutoValuePojoProcessorDelegateTest > goodPojo PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > useFromQueryParameter_forQueryParameter PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > useFromDao_forQueryParameter PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > collection_forEntity PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > useFromEntityField_forReturnValue PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > useFromDatabase_forQueryParameter PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > useFromEntityField_forQueryParameter PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > useFromDatabase_forReturnValue PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > useFromEntity_forQueryParameter PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > useFromQueryMethod_forQueryParameter PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > useFromDatabase_forEntity PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > collection_forDao PASSED
-androidx\.room\.solver\.CustomTypeConverterResolutionTest > useFromEntity_forReturnValue PASSED
-androidx\.room\.solver\.TypeAssignmentTest > unboundedVariance PASSED
-androidx\.room\.solver\.TypeAssignmentTest > variance PASSED
-androidx\.room\.solver\.TypeAssignmentTest > basic PASSED
-androidx\.room\.solver\.TypeAssignmentTest > generics PASSED
-androidx\.room\.solver\.query\.QueryWriterTest > aLongAndIntegerList PASSED
-androidx\.room\.solver\.query\.QueryWriterTest > aLongAndIntegerSet PASSED
-androidx\.room\.solver\.query\.QueryWriterTest > simpleStringArgs PASSED
-androidx\.room\.solver\.query\.QueryWriterTest > aLongAndIntegerImmutableList PASSED
-androidx\.room\.solver\.query\.QueryWriterTest > testMultipleBindParamsWithSameNameWithVarArg PASSED
-androidx\.room\.solver\.query\.QueryWriterTest > simpleNoArgQuery PASSED
-androidx\.room\.solver\.query\.QueryWriterTest > testMultipleBindParamsWithSameNameWithVarArgInTwoBindings PASSED
-androidx\.room\.solver\.query\.QueryWriterTest > aLongAndIntVarArg PASSED
-androidx\.room\.solver\.query\.QueryWriterTest > testMultipleBindParamsWithSameName PASSED
-androidx\.room\.solver\.query\.QueryWriterTest > twoIntArgs PASSED
-androidx\.room\.util\.SimpleJavaVersionTest > testTryParse PASSED
-androidx\.room\.util\.SimpleJavaVersionTest > testComparison PASSED
-androidx\.room\.util\.SimpleJavaVersionTest > testParse PASSED
-androidx\.room\.vo\.EntityTest > shouldBeDeletedAfter PASSED
-androidx\.room\.writer\.AutoMigrationWriterTest > validAutoMigrationWithoutDefaultValue PASSED
-androidx\.room\.writer\.AutoMigrationWriterTest > validAutoMigrationWithDefaultValue PASSED
-androidx\.room\.writer\.EntityCursorConverterWriterTest > generateSimple PASSED
-androidx\.room\.writer\.SQLiteOpenHelperWriterTest > autoIncrementObject PASSED
-androidx\.room\.writer\.SQLiteOpenHelperWriterTest > createSimpleEntity PASSED
-androidx\.room\.writer\.SQLiteOpenHelperWriterTest > createSimpleView PASSED
-androidx\.room\.writer\.SQLiteOpenHelperWriterTest > multiplePrimaryKeys PASSED
-androidx\.room\.writer\.SQLiteOpenHelperWriterTest > autoIncrementPrimitives PASSED
-# > Task :ipc:ipc-compiler:kaptTestKotlin
-Annotation processors discovery from compile classpath is deprecated\.
-Set 'kapt\.include\.compile\.classpath=false' to disable discovery\.
-Set 'kapt\.includeCompileClasspath = false' to disable discovery\.
-Run the build with '\-\-info' for more details\.
-# > Task :room:room-compiler:test
-androidx\.room\.log\.RLogTest > testSafeFormat PASSED
-androidx\.room\.parser\.SqlParserTest > multipleQueries PASSED
-androidx\.room\.parser\.SqlParserTest > invalidColumnNames PASSED
-androidx\.room\.parser\.SqlParserTest > explain PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > projection_containsParameter PASSED
-androidx\.room\.parser\.SqlParserTest > rowValue_where PASSED
-androidx\.room\.parser\.SqlParserTest > tablePrefixInInsert_set PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > projection PASSED
-androidx\.room\.parser\.SqlParserTest > deleteQuery PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > multipleQueries PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > invalidColumnNames PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > explain PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > rowValue_where PASSED
-androidx\.room\.parser\.SqlParserTest > extractTableNames PASSED
-androidx\.room\.parser\.SqlParserTest > unescapeTableNames PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > tablePrefixInInsert_set PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > deleteQuery PASSED
-androidx\.room\.parser\.SqlParserTest > upsertQuery PASSED
-androidx\.room\.parser\.SqlParserTest > updateQuery PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > extractTableNames PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > unescapeTableNames PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > upsertQuery PASSED
-androidx\.room\.parser\.SqlParserTest > selectMultipleBindingParameter PASSED
-androidx\.room\.parser\.SqlParserTest > badDeleteQuery PASSED
-androidx\.room\.parser\.SqlParserTest > insertQuery PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > updateQuery PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > projection_containsExpression PASSED
-androidx\.room\.parser\.SqlParserTest > findBindVariables PASSED
-androidx\.room\.parser\.SqlParserTest > tablePrefixInSelect_projection PASSED
-androidx\.room\.parser\.SqlParserTest > tablePrefixInInsert_where PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > splitSections PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > projection_columnNames PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > badDeleteQuery PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > insertQuery PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > projection_tableName PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > projection_containsNewline PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > findBindVariables PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > tablePrefixInSelect_projection PASSED
-androidx\.room\.parser\.SqlParserTest > foo PASSED
-androidx\.room\.parser\.SqlParserTest > insertMultipleBindingParameter PASSED
-androidx\.room\.parser\.SqlParserTest > empty PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > tablePrefixInInsert_where PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > empty PASSED
-androidx\.room\.parser\.SqlParserTest > indexedVariablesError PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > indexedVariablesError PASSED
-androidx\.room\.parser\.SqlParserTest > unicodeInIdentifiers PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > unicodeInIdentifiers PASSED
-androidx\.room\.parser\.SqlParserTest > tablePrefixInSelect_where PASSED
-androidx\.room\.parser\.SqlParserTest > validColumnNames PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > tablePrefixInSelect_where PASSED
-androidx\.room\.parser\.ExpandableSqlParserTest > validColumnNames PASSED
-androidx\.room\.parser\.SqlParserTest > hasTopStarProjection PASSED
-(WARNING: All illegal access operations will be denied in a future release)?WARNING: Illegal reflective access by androidx\.room\.compiler\.processing\.javac\.JavacProcessingEnvMessager\$Companion \(file:\$OUT_DIR/androidx/room/room\-compiler\-processing/build/(classes/kotlin/main/|libs/room\-compiler\-processing\-[0-9]+\.[0-9]+\.[0-9]+(\-(alpha|beta|rc)[0-9]+)?\.jar)\) to field com\.sun\.tools\.javac\.code\.Symbol\$ClassSymbol\.classfile
-(WARNING: All illegal access operations will be denied in a future release)?WARNING: Illegal reflective access by androidx\.room\.compiler\.processing\.javac\.JavacProcessingEnvMessager\$Companion \(file:\$OUT_DIR/androidx/room/room\-compiler\-processing/build/(classes/kotlin/main/|libs/room\-compiler\-processing\-[0-9]+\.[0-9]+\.[0-9]+(\-(alpha|beta|rc)[0-9]+)?\.jar)\) to field com\.sun\.tools\.javac\.code\.Symbol\.owner
-WARNING: Please consider reporting this to the maintainers of androidx\.room\.compiler\.processing\.javac\.JavacProcessingEnvMessager\$Companion
-# > Task :docs-runner:dokkaJavaTipOfTreeDocs
-\$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-stdlib\-jdk[0-9]+/[0-9]+\.[0-9]+\.[0-9]+-?[\-A-Z0-9]*/kotlin\-stdlib\-jdk[0-9]+\-[0-9]+\.[0-9]+\.[0-9]+-?[\-A-Z0-9]*\.jar \(version [0-9]+\.[0-9]+-?[\-A-Z0-9]*\)
 # > Task :compose:ui:ui:processDebugAndroidTestManifest
 \$OUT_DIR/.*/tempFile[0-9]+ProcessTestManifest[0-9]+\.xml Warning:
 Namespace 'androidx\..*' used in: tempFile[0-9]+ProcessTestManifest[0-9]+\.xml, :.*
 \$OUT_DIR/androidx/compose/runtime/runtime\-saveable/build/intermediates/tmp/manifest/androidTest/debug/tempFile[0-9]+ProcessTestManifest[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
 \$OUT_DIR/androidx/compose/ui/ui\-tooling/build/intermediates/tmp/manifest/androidTest/debug/tempFile[0-9]+ProcessTestManifest[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
 # > Task :buildSrc:build UP-TO-DATE
-See the profiling report at\: file\:\/\/\$OUT_DIR\/buildSrc\/build\/reports\/profile\/profile\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\-[0-9]+\.html
 A fine\-grained performance profile is available\: use the \-\-scan option\.
-# > Task :annotation:annotation-experimental-lint:compileKotlin
-w\: ATTENTION\!
-This build uses unsafe internal compiler arguments\:
-This mode is not recommended for production use\,
-as no stability\/compatibility guarantees are given on
-compiler or generated code\. Use it at your own risk\!
-# > Task :docs-public:lintDebug
-Wrote HTML report to file://\$OUT_DIR/androidx/docs\-public/build/reports/lint\-results\-debug\.html
-# > Task :camera:camera-core:compileDebugJavaWithJavac
-warning: unknown enum constant AnnotationRetention\.BINARY
-# > Task :compose:foundation:foundation:reportLibraryMetrics
-java\.lang\.Object androidx\.compose\.foundation\.lazy\.LazyListScrollingKt\$doSmoothScrollToItem\$[0-9]+\.invokeSuspend\(java\.lang\.Object\)
-java\.lang\.Object androidx\.compose\.foundation\.gestures\.ForEachGestureKt\.forEachGesture\(androidx\.compose\.ui\.input\.pointer\.PointerInputScope, kotlin\.jvm\.functions\.Function[0-9]+, kotlin\.coroutines\.Continuation\)
-# > Task :preference:preference:compileDebugAndroidTestKotlin
-w\: \$SUPPORT\/preference\/preference\/src\/androidTest\/java\/androidx\/preference\/tests\/PreferenceDialogFragmentCompatTest\.kt\: \([0-9]+\, [0-9]+\)\: \'setTargetFragment\(Fragment\?\, Int\)\: Unit\' is deprecated\. Deprecated in Java
 # > Task :viewpager2:viewpager2:compileDebugAndroidTestKotlin
 w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/HostFragmentBackStackTest\.kt\: \([0-9]+\, [0-9]+\)\: \'enableDebugLogging\(Boolean\)\: Unit\' is deprecated\. Deprecated in Java
-w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/OnApplyWindowInsetsListenerTest\.kt\: \([0-9]+\, [0-9]+\)\: \'getter for systemWindowInsets\: Insets\' is deprecated\. Deprecated in Java
-w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/OnApplyWindowInsetsListenerTest\.kt\: \([0-9]+\, [0-9]+\)\: \'getter for stableInsets\: Insets\' is deprecated\. Deprecated in Java
-w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/OnApplyWindowInsetsListenerTest\.kt\: \([0-9]+\, [0-9]+\)\: \'setSystemWindowInsets\(Insets\)\: WindowInsetsCompat\.Builder\' is deprecated\. Deprecated in Java
-w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/OnApplyWindowInsetsListenerTest\.kt\: \([0-9]+\, [0-9]+\)\: \'setSystemGestureInsets\(Insets\)\: WindowInsetsCompat\.Builder\' is deprecated\. Deprecated in Java
-w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/OnApplyWindowInsetsListenerTest\.kt\: \([0-9]+\, [0-9]+\)\: \'setStableInsets\(Insets\)\: WindowInsetsCompat\.Builder\' is deprecated\. Deprecated in Java
-w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/OnApplyWindowInsetsListenerTest\.kt\: \([0-9]+\, [0-9]+\)\: \'setTappableElementInsets\(Insets\)\: WindowInsetsCompat\.Builder\' is deprecated\. Deprecated in Java
-w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/OnApplyWindowInsetsListenerTest\.kt\: \([0-9]+\, [0-9]+\)\: \'setMandatorySystemGestureInsets\(Insets\)\: WindowInsetsCompat\.Builder\' is deprecated\. Deprecated in Java
-w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/OnApplyWindowInsetsListenerTest\.kt\: \([0-9]+\, [0-9]+\)\: \'consumeSystemWindowInsets\(\)\: WindowInsetsCompat\' is deprecated\. Deprecated in Java
-w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/OnApplyWindowInsetsListenerTest\.kt\: \([0-9]+\, [0-9]+\)\: Unnecessary non\-null assertion \(\!\!\) on a non\-null receiver of type WindowInsetsCompat
-w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/OnApplyWindowInsetsListenerTest\.kt\: \([0-9]+\, [0-9]+\)\: \'consumeStableInsets\(\)\: WindowInsetsCompat\' is deprecated\. Deprecated in Java
-w\: \$SUPPORT\/viewpager[0-9]+\/viewpager[0-9]+\/src\/androidTest\/java\/androidx\/viewpager[0-9]+\/widget\/OnApplyWindowInsetsListenerTest\.kt\: \([0-9]+\, [0-9]+\)\: \'consumeDisplayCutout\(\)\: WindowInsetsCompat\' is deprecated\. Deprecated in Java
 # > Task :docs-public:dokkaKotlinDocs
 No documentation for .*
 Found an unresolved type in androidx\.compose\.ui\.test\$pressKey\(androidx\.compose\.ui\.test\.KeyInjectionScope, androidx\.compose\.ui\.input\.key\.Key, kotlin\.Int, kotlin\.Long, kotlin\.Long\) \(KeyInjectionScope\.kt:[0-9]+\)
 Found an unresolved type in androidx\.compose\.ui\.test\$pressKeys\(androidx\.compose\.ui\.test\.KeyInjectionScope, kotlin\.collections\.List\(\(androidx\.compose\.ui\.input\.key\.Key\)\), kotlin\.Long, kotlin\.Long\) \(KeyInjectionScope\.kt:[0-9]+\)
-Found an unresolved type in androidx\.compose\.ui\.test\.junit[0-9]+\.AndroidComposeTestRule\$waitForIdle\(\) \(AndroidComposeTestRule\.android\.kt:[0-9]+\)
-Found an unresolved type in androidx\.compose\.ui\.test\.junit[0-9]+\.AndroidComposeTestRule\$awaitIdle\(\) \(AndroidComposeTestRule\.android\.kt:[0-9]+\)
-Found an unresolved type in androidx\.compose\.ui\.test\.junit[0-9]+\.AndroidComposeTestRule\$waitUntil\(kotlin\.Long, kotlin\.Function[0-9]+\(\(kotlin\.Boolean\)\)\) \(AndroidComposeTestRule\.android\.kt:[0-9]+\)
-Found an unresolved type in androidx\.compose\.ui\.test\.junit[0-9]+\.AndroidComposeTestRule\$registerIdlingResource\(androidx\.compose\.ui\.test\.IdlingResource\) \(AndroidComposeTestRule\.android\.kt:[0-9]+\)
-Found an unresolved type in androidx\.compose\.ui\.test\.junit[0-9]+\.AndroidComposeTestRule\$unregisterIdlingResource\(androidx\.compose\.ui\.test\.IdlingResource\) \(AndroidComposeTestRule\.android\.kt:[0-9]+\)
-Found an unresolved type in androidx\.compose\.ui\.test\.junit[0-9]+\.AndroidComposeTestRule\$setContent\(kotlin\.Function[0-9]+\(\(kotlin\.Unit\)\)\) \(AndroidComposeTestRule\.android\.kt:[0-9]+\)
 Found an unresolved type in androidx\.compose\.runtime\.snapshots\.SnapshotStateList\$add\(androidx\.compose\.runtime\.snapshots\.SnapshotStateList\.T\) \(SnapshotStateList\.kt:[0-9]+\)
 Found an unresolved type in androidx\.compose\.runtime\.snapshots\.SnapshotStateList\$addAll\(kotlin\.collections\.Collection\(\(androidx\.compose\.runtime\.snapshots\.SnapshotStateList\.T\)\)\) \(SnapshotStateList\.kt:[0-9]+\)
 Found an unresolved type in androidx\.compose\.runtime\.snapshots\.SnapshotStateList\$remove\(androidx\.compose\.runtime\.snapshots\.SnapshotStateList\.T\) \(SnapshotStateList\.kt:[0-9]+\)
@@ -1387,137 +253,14 @@
 Found an unresolved type in androidx\.paging\.LivePagedListBuilder\$setInitialLoadKey\(androidx\.paging\.LivePagedListBuilder\.Key\) \(LivePagedListBuilder\.kt:[0-9]+\)
 Found an unresolved type in androidx\.paging\.LivePagedListBuilder\$setBoundaryCallback\(androidx\.paging\.PagedList\.BoundaryCallback\(\(androidx\.paging\.LivePagedListBuilder\.Value\)\)\) \(LivePagedListBuilder\.kt:[0-9]+\)
 Found an unresolved type in androidx\.paging\.LivePagedListBuilder\$setFetchExecutor\(java\.util\.concurrent\.Executor\) \(LivePagedListBuilder\.kt:[0-9]+\)
-# > Task :compose:foundation:foundation-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/compose/foundation/foundation/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :compose:material:material-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/compose/material/material/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :compose:foundation:foundation-layout:foundation-layout-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/compose/foundation/foundation\-layout/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :compose:ui:ui-text:ui-text-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/compose/ui/ui\-text/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :compose:benchmark-utils:benchmark-utils-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/compose/benchmark\-utils/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :compose:ui:ui-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/compose/ui/ui/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :compose:animation:animation-core:animation-core-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/compose/animation/animation\-core/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :compose:ui:ui-graphics:ui-graphics-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/compose/ui/ui\-graphics/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :docs-public:doclavaDocs
-\$OUT_DIR/androidx/docs\-public/build/srcs/androidx/activity/OnBackPressedDispatcher\.java:[0-9]+: error: cannot find symbol
-import android\.view\.OnBackInvokedCallback;
-\$OUT_DIR\/androidx\/docs\-public\/build\/srcs\/androidx\/work\/impl\/WorkManagerImpl\.java\:[0-9]+\: error\: cannot find symbol
-import static android\.app\.PendingIntent\.FLAG_MUTABLE\;
 # > Task :docs-public:dackkaDocs
-WARN\: nullability annotation on Kotlin source\.If the annotation cannot be found in source\, it might be unavoidable from inheritance\.
-PROGRESS: Initializing plugins
-Loaded plugins: \[org\.jetbrains\.dokka\.base\.DokkaBase, com\.google\.devsite\.DevsitePlugin\]
-Loaded: \[
-ExtensionPoint: org\.jetbrains\.dokka\.base\.DokkaBase/immediateHtmlCommandConsumer,
-ExtensionPoint: org\.jetbrains\.dokka\.CoreExtensions/pageTransformer,
-ExtensionPoint: org\.jetbrains\.dokka\.base\.DokkaBase/htmlPreprocessors,
-ExtensionPoint: org\.jetbrains\.dokka\.base\.DokkaBase/outputWriter,
-ExtensionPoint: org\.jetbrains\.dokka\.base\.DokkaBase/externalLocationProviderFactory,
-ExtensionPoint: org\.jetbrains\.dokka\.base\.DokkaBase/locationProviderFactory,
-ExtensionPoint: org\.jetbrains\.dokka\.base\.DokkaBase/kotlinAnalysis,
-ExtensionPoint: org\.jetbrains\.dokka\.CoreExtensions/renderer,
-ExtensionPoint: org\.jetbrains\.dokka\.base\.DokkaBase/tabSortingStrategy,
-ExtensionPoint: org\.jetbrains\.dokka\.base\.DokkaBase/pageMergerStrategy,
-ExtensionPoint: org\.jetbrains\.dokka\.base\.DokkaBase/commentsToContentConverter,
-ExtensionPoint: org\.jetbrains\.dokka\.CoreExtensions/documentableToPageTranslator,
-ExtensionPoint: org\.jetbrains\.dokka\.CoreExtensions/documentableTransformer,
-ExtensionPoint: org\.jetbrains\.dokka\.base\.DokkaBase/signatureProvider,
-ExtensionPoint: org\.jetbrains\.dokka\.base\.DokkaBase/preMergeDocumentableTransformer,
-ExtensionPoint: org\.jetbrains\.dokka\.CoreExtensions/documentableMerger,
-ExtensionPoint: org\.jetbrains\.dokka\.CoreExtensions/sourceToDocumentableTranslator,
-ExtensionPoint: org\.jetbrains\.dokka\.CoreExtensions/generation,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/pathToRootConsumer,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/resolveLinkConsumer,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/defaultSamplesTransformer,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/sourceSetMerger,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/pageMerger,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/rootCreator,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/sourcesetDependencyAppender,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/packageListCreator,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/assetsInstaller,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/stylesInstaller,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/scriptsInstaller,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/customResourceInstaller,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/navigationSearchInstaller,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/navigationPageInstaller,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/sourceLinksTransformer,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/baseSearchbarDataInstaller,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/fileWriter,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/dokkaLocationProvider,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/javadocLocationProvider,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/locationProvider,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/defaultKotlinAnalysis,
-Extension: com\.google\.devsite\.DevsitePlugin/renderer,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/defaultTabSortingStrategy,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/sameMethodNameMerger,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/fallbackMerger,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/docTagToContentConverter,
-Extension: com\.google\.devsite\.DevsitePlugin/translator,
-Extension: com\.google\.devsite\.DevsitePlugin/hideFilter,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/extensionsExtractor,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/undocumentedCodeReporter,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/inheritorsExtractor,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/sinceKotlinTransformer,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/actualTypealiasAdder,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/kotlinSignatureProvider,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/modulesAndPackagesDocumentation,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/inheritedEntriesVisbilityFilter,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/obviousFunctionsVisbilityFilter,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/documentableVisibilityFilter,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/suppressedBySuppressTagDocumentableFilter,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/suppressedDocumentableFilter,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/deprecatedDocumentableFilter,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/emptyPackagesFilter,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/emptyModulesFilter,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/documentableMerger,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/psiToDocumentableTranslator,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/descriptorToDocumentableTranslator,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/singleGeneration
-\]
-Suppressed: \[
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/documentableToPageTranslator by Extension: com\.google\.devsite\.DevsitePlugin/translator,
-Extension: org\.jetbrains\.dokka\.base\.DokkaBase/htmlRenderer by Extension: com\.google\.devsite\.DevsitePlugin/renderer
-PROGRESS: Dokka is performing: documentation for
-PROGRESS: Validity check
-PROGRESS: Creating documentation models
 ERROR: An attempt to write .*
 WARN: Unable to find what is referred to by
-Generation completed with.*
 # > Task :docs-tip-of-tree:dackkaDocs
-Conflicting documentation for .*
-PROGRESS: Transforming documentation model before merging
-PROGRESS: Merging documentation models
-PROGRESS: Transforming documentation model after merging
-PROGRESS: Creating pages
-PROGRESS: Transforming pages
-Unused extension points found:.*
-PROGRESS:
-=== TIME MEASUREMENT ===
-Initializing plugins\: *[0-9]+
-Validity check\: *[0-9]+
-Creating documentation models: *[0-9]+
-Transforming documentation model before merging\: *[0-9]+
-Merging documentation models\: *[0-9]+
-Transforming documentation model after merging\: *[0-9]+
-Creating pages\: *[0-9]+
-Transforming pages\: *[0-9]+
-Rendering\: *[0-9]+
-@param _value
-in DClass ObservableWatchData
-@param currentUserStyleRepository,
-@param watchState
-in DClass Renderer
-@param bounds
 in DClass ComplicationSlot
 @param id,
 @param canvasComplicationFactory,
 @param supportedTypes,
-\@param defaultProviderPolicy\,
 @param defaultDataSourcePolicy,
 @param boundsType,
 @param bounds,
@@ -1529,35 +272,11 @@
 Did you make a typo\? Are you trying to refer to something not visible to users\?
 # Wire proto generation, task :generateDebugProtos
 Writing .* to \$OUT_DIR/.*/build/generated/source/wire
-# > Task :docs-tip-of-tree:doclavaDocs
-javadoc\: warning \- Multiple sources of package comments found for package \"javax\.annotation\"
-[0-9]+ warning
-# > Task :stripArchiveForPartialDejetification
-Execution optimizations have been disabled for task ':stripArchiveForPartialDejetification' to ensure correctness due to the following reasons:
-\- Gradle detected a problem with the following location: '\$DIST_DIR/top\-of\-tree\-m2repository\-all\-.*.zip'\. Reason: Task ':stripArchiveForPartialDejetification' uses this output of task ':benchmark:benchmark\-gradle\-plugin:buildOnServer' without declaring an explicit or implicit dependency\. This can lead to incorrect results being produced, depending on what order the tasks are executed\. Please refer to https://docs\.gradle\.org/[0-9]+\.[0-9]+/userguide/validation_problems\.html\#implicit_dependency for more details about this problem\.
-# > Task :icing:lintDebug
-Wrote HTML report to file://\$OUT_DIR/androidx/icing/build/reports/lint\-results\-debug\.html
-# https://youtrack.jetbrains.com/issue/KT-30589
-WARNING: Illegal reflective access by org\.jetbrains\.kotlin\.kapt3\.base\.javac\.KaptJavaFileManager .* to method com\.sun\.tools\.javac\.file\.BaseFileManager\.handleOption\(com\.sun\.tools\.javac\.main\.Option,java\.lang\.String\)
-# > Task :benchmark:benchmark-macro:compileReleaseKotlin
-Execution optimizations have been disabled for task ':benchmark:benchmark\-common:.*' to ensure correctness due to the following reasons:
-\- Gradle detected a problem with the following location: '\$OUT_DIR/androidx/benchmark/benchmark\-macro/build/generated/source/wire'\. Reason: Task ':benchmark:benchmark\-macro:.*' uses this output of task ':benchmark:benchmark\-macro:.*' without declaring an explicit or implicit dependency\. This can lead to incorrect results being produced, depending on what order the tasks are executed\. Please refer to https://docs\.gradle\.org/[0-9]+\.[0-9]+/userguide/validation_problems\.html\#implicit_dependency for more details about this problem\.
-# > Task :profileinstaller:profileinstaller:processDebugUnitTestManifest
-Scanning .+: \.*
 # > Task :compose:ui:ui-tooling:processDebugAndroidTestManifest
 \$SUPPORT/compose/ui/ui\-tooling/src/androidAndroidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-No issues found.*
 dagger\.lint\.DaggerIssueRegistry in .*/lint\.jar does not specify a vendor; see IssueRegistry#vendor
 # > Task :compose:foundation:foundation:androidReleaseSourcesJar
 Encountered duplicate path "android[a-zA-Z]*/.+" during copy operation configured with DuplicatesStrategy\.WARN
-# > Task :profileinstaller:profileinstaller-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/profileinstaller/profileinstaller\-benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Task :wear:compose:compose-material-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/wear/compose/compose\-material/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-\$SUPPORT/wear/compose/material/benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Configure project :ads-identifier
-WARNING\:The option setting \'android\.experimental\.enableArtProfiles\=true\' is experimental\.
-The current default is \'false\'\.
 # ./gradlew tasks warns as we have warnings present
 You can use \'\-\-warning\-mode all\' to show the individual deprecation warnings and determine if they come from your own scripts or plugins\.
 # > Task :emoji2:emoji2-bundled:processDebugAndroidTestManifest
@@ -1565,19 +284,10 @@
 meta\-data\#androidx\.emoji[0-9]+\.text\.EmojiCompatInitializer was tagged at AndroidManifest\.xml:[0-9]+ to remove other declarations but no other declaration present
 # > Task :emoji2:emoji2-bundled:processDebugManifest
 \$SUPPORT/emoji[0-9]+/emoji[0-9]+\-bundled/src/main/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
-# > Configure project :emoji2:emoji2-bundled
-WARNING:The option setting 'android\.disableAutomaticComponentCreation=true' is experimental\.
-# > Task :navigation:navigation-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/navigation/navigation\-benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
 # b/195025261
-Unable to detect AGP versions for included builds\. All projects in the build should use the same AGP version\. Class name for the included build .*
-\- Gradle detected a problem with the following location: '\$OUT_DIR/androidx/benchmark/benchmark-common/build/generated/source/wire'\. Reason: Task ':benchmark:benchmark-common:.*' uses this output of task ':benchmark:benchmark-common:generate(Debug|Release)Protos' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed. Please refer to .*
 To honour the JVM settings for this build a single\-use Daemon process will be forked.*
 # > Task :work:work-benchmark:processReleaseAndroidTestManifest
-\$SUPPORT/work/work\-benchmark/src/androidTest/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
 [0-9]+ problems were found storing the configuration cache\.
-[0-9]+ problems were found storing the configuration cache, [0-9]+ of which seems unique\.
-Calculating task graph as configuration cache cannot be reused because the set of Gradle properties has changed.
 # > Task :car:app:app:generateProtocolApi
 \- Task `:car:app:app:generateProtocolApi` of type `GenerateProtocolApiTask`: invocation of 'Task\.project' at execution time is unsupported\.
 # > Tasks configureCMakeRelWithDebInfo or configureCMakeDebug
@@ -1588,15 +298,11 @@
 Info: Stripped invalid locals information from [0-9]+ methods?\.
 Info: Methods with invalid locals information:
 void androidx\.wear\.compose\.material\.PickerKt\.Picker\-gjPtlC[0-9]+\(androidx\.wear\.compose\.material\.PickerState, java\.lang\.String, androidx\.compose\.ui\.Modifier, boolean, kotlin\.jvm\.functions\.Function[0-9]+, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.wear\.compose\.material\.ScalingParams, float, float, long, androidx\.compose\.foundation\.gestures\.FlingBehavior, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.runtime\.Composer, int, int, int\)
-void androidx\.wear\.compose\.material\.PickerKt\.Picker\-gjPtlC[0-9]+\(androidx\.wear\.compose\.material\.PickerState, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.ui\.Modifier, boolean, kotlin\.jvm\.functions\.Function[0-9]+, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.wear\.compose\.material\.ScalingParams, float, float, long, androidx\.compose\.foundation\.gestures\.FlingBehavior, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.runtime\.Composer, int, int, int\)
-java\.lang\.Object androidx\.glance\.state\.GlanceState\.getDataStore\(android\.content\.Context, androidx\.glance\.state\.GlanceStateDefinition, java\.lang\.String, kotlin\.coroutines\.Continuation\)
-Information in locals\-table is invalid with respect to the stack map table\. Local refers to non\-present stack map type for register: [0-9]+ with constraint OBJECT\.
 # https://youtrack.jetbrains.com/issue/KT-52702/
 void androidx\.compose\.animation\.demos\.visualaid\.EasingFunctionDemoKt\.EasingInfoDemo\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.foundation\.text\.CoreTextFieldKt\.CoreTextField\(androidx\.compose\.ui\.text\.input\.TextFieldValue, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.ui\.Modifier, androidx\.compose\.ui\.text\.TextStyle, androidx\.compose\.ui\.text\.input\.VisualTransformation, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.foundation\.interaction\.MutableInteractionSource, androidx\.compose\.ui\.graphics\.Brush, boolean, int, androidx\.compose\.ui\.text\.input\.ImeOptions, androidx\.compose\.foundation\.text\.KeyboardActions, boolean, boolean, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.runtime\.Composer, int, int, int\)
 void androidx\.compose\.material\.ModalBottomSheetKt\.ModalBottomSheetLayout\-BzaUkTc\(kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.ui\.Modifier, androidx\.compose\.material\.ModalBottomSheetState, androidx\.compose\.ui\.graphics\.Shape, float, long, long, long, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.runtime\.Composer, int, int\)
 java\.lang\.Object androidx\.compose\.runtime\.external\.kotlinx\.collections\.immutable\.implementations\.immutableSet\.TrieNode\.mutableRetainAll\(androidx\.compose\.runtime\.external\.kotlinx\.collections\.immutable\.implementations\.immutableSet\.TrieNode, int, androidx\.compose\.runtime\.external\.kotlinx\.collections\.immutable\.internal\.DeltaCounter, androidx\.compose\.runtime\.external\.kotlinx\.collections\.immutable\.implementations\.immutableSet\.PersistentHashSetBuilder\)
-void androidx\.compose\.material[0-9]+\.SliderKt\$RangeSlider\$[0-9]+\.invoke\(androidx\.compose\.foundation\.layout\.BoxWithConstraintsScope, androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.integration\.docs\.layout\.MaterialSnippet[0-9]+\.MyBackdrop\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.wear\.compose\.material\.samples\.PickerSampleKt\.OptionChangePicker\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.foundation\.samples\.MutatorMutexSamplesKt\.mutatorMutexStateObject\$ScrollControls\(androidx\.compose\.foundation\.samples\.MutatorMutexSamplesKt\$mutatorMutexStateObject\$ScrollState, androidx\.compose\.runtime\.Composer, int\)
@@ -1606,13 +312,9 @@
 void androidx\.paging\.compose\.demos\.room\.PagingRoomSampleKt\.PagingRoomDemo\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.material[0-9]+\.catalog\.library\.ui\.common\.CatalogScaffoldKt\.CatalogScaffold\(java\.lang\.String, boolean, androidx\.compose\.material[0-9]+\.catalog\.library\.model\.Theme, java\.lang\.String, java\.lang\.String, java\.lang\.String, java\.lang\.String, java\.lang\.String, java\.lang\.String, java\.lang\.String, kotlin\.jvm\.functions\.Function[0-9]+, kotlin\.jvm\.functions\.Function[0-9]+, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.runtime\.Composer, int, int, int\)
 void androidx\.compose\.material\.catalog\.library\.ui\.common\.CatalogScaffoldKt\.CatalogScaffold\(java\.lang\.String, boolean, androidx\.compose\.material\.catalog\.library\.model\.Theme, java\.lang\.String, java\.lang\.String, java\.lang\.String, java\.lang\.String, java\.lang\.String, java\.lang\.String, java\.lang\.String, kotlin\.jvm\.functions\.Function[0-9]+, kotlin\.jvm\.functions\.Function[0-9]+, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.runtime\.Composer, int, int, int\)
-void androidx\.compose\.animation\.demos\.FancyScrollingDemoKt\.FancyScrollingDemo\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.foundation\.demos\.relocation\.BringIntoViewAndroidInteropDemoKt\.BringIntoViewAndroidInteropDemo\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.ui\.demos\.keyinput\.InterceptEnterToSendMessageDemoKt\.InterceptEnterToSendMessageDemo\(androidx\.compose\.runtime\.Composer, int\)
-long androidx\.compose\.ui\.input\.pointer\.util\.VelocityTracker\.getImpulseVelocity.*
-java\.lang\.Object androidx\.glance\.state\.GlanceState\.getDataStore\(android\.content\.Context, androidx\.glance\.state\.GlanceStateDefinition, java\.lang\.String, kotlin\.coroutines\.Continuation\)
 Information in locals\-table is invalid with respect to the stack map table\. Local refers to non\-present stack map type for register: [0-9]+ with constraint [\-A-Z]*\.
-java\.lang\.Object androidx\.compose\.foundation\.gestures\.DragGestureDetectorKt\$detectDragGestures\$[0-9]+\$[0-9]+\.invokeSuspend\(java\.lang\.Object\)
 void androidx\.compose\.animation\.demos\.visualaid\.EasingFunctionDemoKt\.EasingGraph\(androidx\.compose\.animation\.core\.Easing, androidx\.compose\.ui\.Modifier, kotlinx\.coroutines\.CoroutineScope, androidx\.compose\.runtime\.Composer, int, int\)
 void androidx\.compose\.animation\.demos\.gesture\.FancyScrollingDemoKt\.FancyScrollingDemo\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.animation\.demos\.suspendfun\.SuspendDoubleTapToLikeDemoKt\.SuspendDoubleTapToLikeDemo\(androidx\.compose\.runtime\.Composer, int\)
@@ -1629,7 +331,6 @@
 void androidx\.compose\.material[0-9]+\.NavigationDrawerKt\.ModalNavigationDrawer\-Gs[0-9]+lGvM\(kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.ui\.Modifier, androidx\.compose\.material[0-9]+\.DrawerState, boolean, androidx\.compose\.ui\.graphics\.Shape, float, long, long, long, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.runtime\.Composer, int, int\)
 void androidx\.compose\.material[0-9]+\.SwitchKt\.Switch\(boolean, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.ui\.Modifier, kotlin\.jvm\.functions\.Function[0-9]+, boolean, androidx\.compose\.foundation\.interaction\.MutableInteractionSource, androidx\.compose\.material[0-9]+\.SwitchColors, androidx\.compose\.runtime\.Composer, int, int\)
 void androidx\.compose\.material[0-9]+\.NavigationDrawerKt\.DismissibleNavigationDrawer\-ZEC[0-9]+aPw\(kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.ui\.Modifier, androidx\.compose\.material[0-9]+\.DrawerState, boolean, androidx\.compose\.ui\.graphics\.Shape, float, long, long, kotlin\.jvm\.functions\.Function[0-9]+, androidx\.compose\.runtime\.Composer, int, int\)
-void androidx\.compose\.material[0-9]+\.SliderKt\$Slider\$[0-9]+\.invoke\(androidx\.compose\.foundation\.layout\.BoxWithConstraintsScope, androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.material[0-9]+\.TabRowKt\$ScrollableTabRow\$[0-9]+\.invoke\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.integration\.docs\.layout\.MaterialSnippet[0-9]+\.MyDrawer\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.integration\.docs\.layout\.MaterialSnippet[0-9]+\.MyBottomSheet\(androidx\.compose\.runtime\.Composer, int\)
@@ -1657,31 +358,21 @@
 void androidx\.compose\.material[0-9]+\.samples\.ScaffoldSamplesKt\.ScaffoldWithIndefiniteSnackbar\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.material[0-9]+\.samples\.ScaffoldSamplesKt\.ScaffoldWithCustomSnackbar\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.ui\.samples\.FocusAwareInputSamplesKt\.RotaryEventSample\(androidx\.compose\.runtime\.Composer, int\)
-void androidx\.compose\.animation\.demos\.SuspendDoubleTapToLikeDemoKt\.SuspendDoubleTapToLikeDemo\(androidx\.compose\.runtime\.Composer, int\)
-void androidx\.compose\.animation\.demos\.EasingFunctionDemoKt\.EasingInfoDemo\(androidx\.compose\.runtime\.Composer, int\)
-void androidx\.compose\.animation\.demos\.EasingFunctionDemoKt\.EasingGraph\(androidx\.compose\.animation\.core\.Easing, androidx\.compose\.ui\.Modifier, kotlinx\.coroutines\.CoroutineScope, androidx\.compose\.runtime\.Composer, int, int\)
 void androidx\.compose\.foundation\.demos\.relocation\.RequestRectangleOnScreenDemoKt\.RequestRectangleOnScreenDemo\(androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.foundation\.demos\.relocation\.BringIntoViewDemoKt\.BringIntoViewDemo\(androidx\.compose\.runtime\.Composer, int\)
-void androidx\.compose\.foundation\.demos\.relocation\.BringNestedIntoViewDemoKt\.ControlGrid\(int, int, java\.util\.List, androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.foundation\.demos\.ListDemosKt\.ListHoistedStateDemo\(androidx\.compose\.runtime\.Composer, int\)
 androidx\.compose\.ui\.Modifier androidx\.compose\.ui\.demos\.modifier\.CommunicatingModifierDemoKt\$CommunicatingModifierDemo\$clickToRead\$[0-9]+\.invoke\(androidx\.compose\.ui\.Modifier, androidx\.compose\.runtime\.Composer, int\)
 void androidx\.compose\.ui\.demos\.focus\.ComposableSingletons\$LazyListChildFocusDemosKt\$lambda\-[0-9]+\$[0-9]+\.invoke\(androidx\.compose\.foundation\.lazy\.LazyItemScope, androidx\.compose\.runtime\.Composer, int\)
 Info: Some warnings are typically a sign of using an outdated Java toolchain\. To fix, recompile the source with an updated toolchain\.
-# > Task :compose:ui:ui-inspection:buildCMakeRelWithDebInfo[arm64-v8a]
-C/C\+\+: ninja: warning: bad deps log signature or version; starting over
-# > Task :textclassifier:integration-tests:testapp:compileReleaseJavaWithJavac
-# > Task :room:integration-tests:room-testapp-kotlin:kspWithKspDebugAndroidTestKotlin
 w: \[ksp\] Using @JvmName annotation on a function or accessor that will be overridden by Room is not supported\. If this is important for your use case, please file a bug at https://issuetracker\.google\.com/issues/new\?component=[0-9]+ with details\. \- androidx\.room\.androidx\.room\.integration\.kotlintestapp\.test\.JvmNameInDaoTest\.JvmNameDb\.jvmDao\(\)
 w: \[ksp\] \$SUPPORT/room/integration\-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/JvmNameInDaoTest\.kt:[0-9]+: Using @JvmName annotation on a function or accessor that will be overridden by Room is not supported\. If this is important for your use case, please file a bug at https://issuetracker\.google\.com/issues/new\?component=[0-9]+ with details\.
 # > Task :room:integration-tests:room-testapp-kotlin:kaptWithKaptDebugAndroidTestKotlin
 \$OUT_DIR/androidx/room/integration\-tests/room\-testapp\-kotlin/build/tmp/kapt[0-9]+/stubs/withKaptDebugAndroidTest/androidx/room/androidx/room/integration/kotlintestapp/test/JvmNameInDaoTest\.java:[0-9]+: warning: Using @JvmName annotation on a function or accessor that will be overridden by Room is not supported\. If this is important for your use case, please file a bug at https://issuetracker\.google\.com/issues/new\?component=[0-9]+ with details\.
+public abstract void jvmDelete\(T t\);
+public abstract void jvmInsert\(@org\.jetbrains\.annotations\.NotNull\(\)
+public abstract java\.util\.List<androidx\.room\.androidx\.room\.integration\.kotlintestapp\.test\.JvmNameInDaoTest\.JvmNameEntity> jvmQuery\(\);
 public abstract androidx\.room\.androidx\.room\.integration\.kotlintestapp\.test\.JvmNameInDaoTest\.JvmNameDao jvmDao\(\);
-# > Task :hilt:integration-tests:hilt-testapp-worker:kaptGenerateStubsDebugUnitTestKotlin
-at org\.jetbrains\.kotlin\.compilerRunner\.GradleCompilerRunner\.runCompilerAsync\(GradleKotlinCompilerRunner\.kt:[0-9]+\)
-at org\.jetbrains\.kotlin\.compilerRunner\.GradleCompilerRunner\.runJvmCompilerAsync\(GradleKotlinCompilerRunner\.kt:[0-9]+\)
-at org\.jetbrains\.kotlin\.gradle\.tasks\.KotlinCompile\.callCompilerAsync\$kotlin_gradle_plugin\(Tasks\.kt:[0-9]+\)
-at org\.jetbrains\.kotlin\.gradle\.tasks\.AbstractKotlinCompile\.executeImpl\(Tasks\.kt:[0-9]+\)
-at org\.jetbrains\.kotlin\.gradle\.tasks\.AbstractKotlinCompile\.execute\(Tasks\.kt:[0-9]+\)
+\^
 # Gradle will log if you are not authenticated to upload scans
 A build scan was not published as you have not authenticated with server 'ge\.androidx\.dev'\.
 # > Task :core:core:processDebugAndroidTestManifest
@@ -1712,8 +403,6 @@
 Found an unresolved type in androidx\.room\.RoomDatabase\.Builder\$setQueryCallback\(androidx\.room\.RoomDatabase\.QueryCallback, java\.util\.concurrent\.Executor\) \(RoomDatabase\.kt:[0-9]+\)
 Found an unresolved type in androidx\.room\.RoomDatabase\.Builder\$addTypeConverter\(kotlin\.Any\) \(RoomDatabase\.kt:[0-9]+\)
 Found an unresolved type in androidx\.room\.RoomDatabase\.Builder\$setAutoCloseTimeout\(kotlin\.Long, java\.util\.concurrent\.TimeUnit\) \(RoomDatabase\.kt:[0-9]+\)
-# > Task :room:integration-tests:room-testapp:mergeDexWithExpandProjectionDebugAndroidTest b/233674378
-WARNING:D8: Application does not contain `androidx\.tracing\.Trace` as referenced in main-dex-list\.
 # > Task :compose:ui:ui:compileReleaseKotlin
 w: \$SUPPORT/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat\.android\.kt: \([0-9]+, [0-9]+\): Unnecessary non\-null assertion \(!!\) on a non\-null receiver of type LayoutNode
 # When konan is downloading a dependency from another file, don't warn about it.
@@ -1740,3 +429,26 @@
 # > Task :tv:tv-material:processReleaseManifest
 # > Task :tv:tv-foundation:processReleaseManifest
 package="androidx\.tv\..*" found in source AndroidManifest\.xml: \$OUT_DIR/androidx/tv/tv\-[a-z]+/build/intermediates/tmp/ProcessLibraryManifest/[a-z]+/tempAndroidManifest[0-9]+\.xml\.
+# > Task :room:integration-tests:room-testapp:mergeDexWithExpandProjectionDebugAndroidTest
+WARNING:D[0-9]+: Application does not contain `androidx\.tracing\.Trace` as referenced in main\-dex\-list\.
+# > Task :hilt:hilt-compiler:kaptTestKotlin
+Annotation processors discovery from compile classpath is deprecated\.
+Set 'kapt\.include\.compile\.classpath=false' to disable discovery\.
+Run the build with '\-\-info' for more details\.
+# > Task :health:health-connect-client:testDebugUnitTest
+WARNING: An illegal reflective access operation has occurred
+WARNING: Illegal reflective access by org\.robolectric\.util\.ReflectionHelpers\$[0-9]+ \(file:\$CHECKOUT/prebuilts/androidx/external/org/robolectric/shadowapi/[0-9]+\.[0-9]+\.[0-9]+/shadowapi\-[0-9]+\.[0-9]+\.[0-9]+\.jar\) to field java\.io\.FileDescriptor\.fd
+WARNING: Please consider reporting this to the maintainers of org\.robolectric\.util\.ReflectionHelpers\$[0-9]+
+WARNING: Use \-\-illegal\-access=warn to enable warnings of further illegal reflective access operations
+WARNING: All illegal access operations will be denied in a future release
+# > Task :room:room-compiler-processing-testing:test
+WARNING: Illegal reflective access by androidx\.room\.compiler\.processing\.javac\.JavacProcessingEnvMessager\$Companion \(file:\$OUT_DIR/androidx/room/room\-compiler\-processing/build/libs/room\-compiler\-processing\-[0-9]+\.[0-9]+\.[0-9]+\-alpha[0-9]+\.jar\) to field com\.sun\.tools\.javac\.code\.Symbol\.owner
+WARNING: Please consider reporting this to the maintainers of androidx\.room\.compiler\.processing\.javac\.JavacProcessingEnvMessager\$Companion
+# > Task :room:room-compiler:test
+WARNING: Illegal reflective access by androidx\.room\.compiler\.processing\.javac\.JavacProcessingEnvMessager\$Companion \(file:\$OUT_DIR/androidx/room/room\-compiler\-processing/build/libs/room\-compiler\-processing\-[0-9]+\.[0-9]+\.[0-9]+\-alpha[0-9]+\.jar\) to field com\.sun\.tools\.javac\.code\.Symbol\$ClassSymbol\.classfile
+# > Task :room:room-compiler-processing:test
+WARNING: Illegal reflective access by org\.jetbrains\.kotlin\.kapt[0-9]+\.base\.javac\.KaptJavaFileManager \(file:\$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-annotation\-processing\-embeddable/[0-9]+\.[0-9]+\.[0-9]+/kotlin\-annotation\-processing\-embeddable\-[0-9]+\.[0-9]+\.[0-9]+\.jar\) to method com\.sun\.tools\.javac\.file\.BaseFileManager\.handleOption\(com\.sun\.tools\.javac\.main\.Option,java\.lang\.String\)
+WARNING: Please consider reporting this to the maintainers of org\.jetbrains\.kotlin\.kapt[0-9]+\.base\.javac\.KaptJavaFileManager
+# > Task :car:app:app-testing:testDebugUnitTest
+WARNING: Illegal reflective access by org\.robolectric\.interceptors\.AndroidInterceptors\$FileDescriptorInterceptor to field java\.io\.FileDescriptor\.fd
+WARNING: Please consider reporting this to the maintainers of org\.robolectric\.interceptors\.AndroidInterceptors\$FileDescriptorInterceptor
\ No newline at end of file
diff --git a/development/gradleRemoteCache/.gitignore b/development/gradleRemoteCache/.gitignore
deleted file mode 100644
index f23b948..0000000
--- a/development/gradleRemoteCache/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.jar
\ No newline at end of file
diff --git a/development/gradleRemoteCache/OWNERS b/development/gradleRemoteCache/OWNERS
deleted file mode 100644
index 3235a23..0000000
--- a/development/gradleRemoteCache/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
[email protected]
\ No newline at end of file
diff --git a/development/gradleRemoteCache/README.md b/development/gradleRemoteCache/README.md
deleted file mode 100644
index 328b00f..0000000
--- a/development/gradleRemoteCache/README.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Setting up the Gradle Build Cache Node on Google Cloud Platform.
-
-To setup the [Gradle Remote Cache](https://docs.gradle.com/build-cache-node) you need to do the following:
-
-## Create a new Instance
-
-* Open the Cloud Platform [console](https://console.cloud.google.com/home/dashboard?project=fetch-licenses).
-
-* In the search box type in and select `VM Instances`.
-
-* Click on an existing node to see details page, then use `Create Similar` to create a new node.
-  *Note*: This node has to be tagged with a network tag called `gradle-remote-cache-node`
-  for it to be picked up by the load balancer. Make sure you create the node in the zone `us-east-1-b`.
-
-* Click `Allow HTTP Traffic` and `Allow HTTPs Traffic`. By doing do, you are allowing UberProxy access
-  to the remote cache. The load balancer is only available when you are on a corp network.
-
-* Connect to the newly created node using an SSH session. You can use the `gcloud` CLI for this.
-  *Note*: Use the `external` IP of the newly created node to SSH.
-
-```bash
-# Note: To switch projects use `gcloud config set project fetch-licenses`
-# Will show the newly created instance
-gcloud compute instances list
-# Will setup ssh configurations
-gcloud compute config-ssh
-ssh 123.123.123.123
-```
-
-## Starting the Gradle Remote Cache Node
-
-```bash
-# Install some prerequisite packages
-sudo apt update
-sudo apt upgrade
-sudo apt install openjdk-11-jdk tmux wget
-# Create a folder `Workspace` in the home directory.
-mkdir Workspace
-cd Workspace
-mkdir -p data/conf
-# using the template in this checkout create config.yaml
-vi data/conf/config.yaml
-# using the template in this checkout create run_node, replace YOURUSERNAME with your username
-vi run_node
-chmod +x run_node
-mkdir gradle-node
-wget https://docs.gradle.com/build-cache-node/jar/build-cache-node-11.1.jar -P gradle-node
-# Create a `tmux` session
-tmux new -s gradle
-sudo ./run_node &
-# Detach from the tmux session ctrl+b then d
-exit
-```
-
-## Update the `gradle-remote-cache-group` instance group.
-
-* Open `Instance groups` in gcloud console
-* Click on `gradle-remote-cache-group` and select `Edit Group`.
-* Select the new node(s), from the drop-down list.
-* Remove old nodes from the list
-* Click `Save`.
diff --git a/development/gradleRemoteCache/config.yaml b/development/gradleRemoteCache/config.yaml
deleted file mode 100644
index 5c5a832..0000000
--- a/development/gradleRemoteCache/config.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-version: 3
-uiAccess:
-  type: "open"
-cache:
-  accessControl:
-    anonymousLevel: "readwrite"
-  targetSize: 150000
-  maxArtifactSize: 2500
diff --git a/development/gradleRemoteCache/gradle-node/.empty b/development/gradleRemoteCache/gradle-node/.empty
deleted file mode 100644
index e69de29..0000000
--- a/development/gradleRemoteCache/gradle-node/.empty
+++ /dev/null
diff --git a/development/gradleRemoteCache/run_node b/development/gradleRemoteCache/run_node
deleted file mode 100644
index 0b50c0f..0000000
--- a/development/gradleRemoteCache/run_node
+++ /dev/null
@@ -1 +0,0 @@
-java -jar /home/YOURUSERNAME/Workspace/gradle-node/build-cache-node-11.1.jar start --data-dir /home/YOURUSERNAME/Workspace/data --port 80 --no-warn-anon-cache-write --no-warn-anon-ui-access
\ No newline at end of file
diff --git a/development/importMaven/.gitignore b/development/importMaven/.gitignore
deleted file mode 100644
index 8173ab4..0000000
--- a/development/importMaven/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-buildSrc/build/
diff --git a/development/importMaven/OWNERS b/development/importMaven/OWNERS
index 7c7f8dd..3e20596 100644
--- a/development/importMaven/OWNERS
+++ b/development/importMaven/OWNERS
@@ -1 +1,3 @@
 [email protected]
[email protected]
[email protected]
\ No newline at end of file
diff --git a/development/importMaven/README.md b/development/importMaven/README.md
index a9fd54f..9ec5b89 100644
--- a/development/importMaven/README.md
+++ b/development/importMaven/README.md
@@ -1,8 +1,43 @@
-## Import From Maven
+Helper script to download prebuilts for offline builds.
 
-#### Using the script
+It can download maven artifacts or KMP prebuilts.
 
-```bash
-./import_maven_artifacts.py --name=androidx.work:work-runtime:1.0.0
-./import_maven_artifacts.py --name=androidx.work:work-runtime:1.0.0,junit:junit:4.12
+By default, arguments passed into it the script that do not immediately
+follow an option (e.g. --optionName value) are evaluated to be maven
+artficat coordinates.
+
+# Quickstart
+
+## download single artifact
+`./importMaven.sh androidx.room:room-runtime:2.4.2`
+`./importMaven.sh --artifacts androidx.room:room-runtime:2.4.2`
+
+## download multiple artifacts
+`./importMaven.sh androidx.room:room-runtime:2.4.2 com.squareup.okio:okio:3.0.0`
+
+## download multiple artifacts with explicit argument
+`./importMaven.sh --artifacts androidx.room:room-runtime:2.4.2,com.squareup.okio:okio:3.0.0`
+
+## download konan prebuilts needed for kotlin native
+`./importMaven.sh import-konan-binaries --konan-compiler-version 1.6.1`
+
+## download everything in the dependencies file of AndroidX
+`./importMaven.sh import-toml`
+
+## download an androidx prebuilt (via androidx.dev)
+`./importMaven.sh --androidx-build-id 123 androidx.room:room-runtime:2.5.0-SNAPSHOT androidx.room:room-compiler:2.5.0-SNAPSHOT`
+
+## download metalava
+`./importMaven.sh --metalava-build-id 8660637 --redownload  --artifacts com.android.tools.metalava:metalava:1.0.0-alpha06`
+
+## verbose logging
+`./importMaven.sh --verbose androidx.room:room-runtime:2.4.2`
+
+# More Help:
+
+For full list of options, please execute one of the commands with `--help`
 ```
+./importMaven.sh --help
+./importMaven.sh import-konan-prebuilts --help
+./importMaven.sh import-toml --help
+```
\ No newline at end of file
diff --git a/development/importMaven/build.gradle.kts b/development/importMaven/build.gradle.kts
index 9a950d6..c91e874 100644
--- a/development/importMaven/build.gradle.kts
+++ b/development/importMaven/build.gradle.kts
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * 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.
@@ -14,571 +14,66 @@
  * limitations under the License.
  */
 
-import okhttp3.MediaType.Companion.toMediaType
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import okhttp3.RequestBody.Companion.toRequestBody
-import org.w3c.dom.Element
-import org.w3c.dom.Node
-import java.security.MessageDigest
-import javax.xml.parsers.DocumentBuilderFactory
-import javax.xml.transform.OutputKeys
-import javax.xml.transform.TransformerFactory
-import javax.xml.transform.dom.DOMSource
-import javax.xml.transform.stream.StreamResult
-import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
-buildscript {
-    // Set of repositories only used for this build.gradle.kts itself. These are not used
-    // for fetching artifacts
-    repositories {
-        mavenCentral()
-    }
-
-    dependencies {
-        classpath("org.apache.maven:maven-model:3.5.4")
-        classpath("org.apache.maven:maven-model-builder:3.5.4")
-        classpath("com.squareup.okhttp3:okhttp:4.8.1")
-        classpath("javax.inject:javax.inject:1")
-    }
-}
-
-// The output folder inside prebuilts
-val prebuiltsLocation = file("../../../../prebuilts/androidx")
-val internalFolder = "internal"
-val externalFolder = "external"
-/**
- * The coordinates of the desired artifact to be fetched with all of its dependencies, specified
- * to the script via -PartifactNames="foo:bar:1.0" or -PartifactNames="foo:bar:1.0,foz:baz:1.0"
- */
-var artifactNames = project.findProperty("artifactNames")?.toString()?.split(",")
-    ?: throw GradleException("You are required to specify -PartifactNames property")
-val kmpBuild = project.findProperty("kmpBuild")?.toString()?.toBoolean() ?: false
-val mediaType = "application/json; charset=utf-8".toMediaType()
-val licenseEndpoint = "https://fetch-licenses.appspot.com/convert/licenses"
-
-val internalArtifacts = listOf(
-    "android.arch(.*)?".toRegex(),
-    "com.android.support(.*)?".toRegex()
-)
-
-val potentialInternalArtifacts = listOf(
-    "androidx(.*)?".toRegex()
-)
-
-// Need to exclude androidx.databinding
-val forceExternal = setOf(
-    ".databinding"
-)
-
-// Apply java plugin so we have a base project set up with runtime configuration and ability to
-// add our requested dependency passed it through the gradle property -PartifactNames="foo:bar:1.0"
 plugins {
-    java
-    alias(libs.plugins.kotlinMp)
+    alias(libs.plugins.kotlinJvm)
+    application
 }
 
-kotlin {
-    jvm()
-    if (kmpBuild) {
-        macosX64()
-        macosArm64()
-        linuxX64()
-        mingwX64()
-        mingwX86()
-        sourceSets {
-            val commonMain by getting {
-                dependencies {
-                    for (artifactName in artifactNames) {
-                        implementation(artifactName)
-                    }
-                }
-            }
-        }
-    }
+group = "androidx.build"
+version = "1.0-SNAPSHOT"
+
+// create a config file that ships in resources so that we can detect the repository layout at
+// runtime.
+val writeConfigPropsTask = tasks.register("prepareEnvironmentProps", WriteProperties::class) {
+    description =  "Generates a properties file with the current environment"
+    setOutputFile(project.layout.buildDirectory.map {
+        it.file("importMavenConfig.properties")
+    })
+    property("supportRoot", project.projectDir.resolve("../../").canonicalPath)
 }
 
-val androidxBuildId: String? = findProperty("androidxBuildId") as String?
-val metalavaBuildId: String? = findProperty("metalavaBuildId") as String?
-
-// Set up repositories from this to fetch the artifacts
-repositories {
-    if (androidxBuildId != null) {
-        maven(url="https://androidx.dev/snapshots/builds/${androidxBuildId}/artifacts/repository")
-    }
-    // Metalava has to be early in the list because it is also published on google() and we
-    // sometimes re-use versions
-    if (metalavaBuildId != null) {
-        maven(url="https://androidx.dev/metalava/builds/${metalavaBuildId}/artifacts/repo/m2repository")
-    }
-    mavenCentral()
-    google()
-    gradlePluginPortal()
-
-    val allowJetbrainsDev: String? = findProperty("allowJetbrainsDev") as String?
-    if (allowJetbrainsDev != null) {
-        maven {
-            url = uri("https://maven.pkg.jetbrains.space/kotlin/p/dokka/dev/")
-            metadataSources {
-                artifact()
-            }
-        }
-        maven {
-            url = uri("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev")
-            metadataSources {
-                artifact()
-            }
-        }
-        maven {
-            url = uri("https://maven.pkg.jetbrains.space/public/p/compose/dev")
-            metadataSources {
-                artifact()
-            }
-        }
-    }
-
-    listOf("macos", "macos-x86_64", "linux", "linux-x86_64").forEach { platstring ->
-        ivy {
-            setUrl("https://download.jetbrains.com/kotlin/native/builds/releases")
-            patternLayout {
-                artifact("[revision]/$platstring/[artifact]-[revision].[ext]")
-            }
-            metadataSources {
-                artifact()
-            }
-            content {
-                includeGroup("")
-            }
-        }
-    }
+val createPropertiesResourceDirectoryTask = tasks.register("createPropertiesResourceDirectory", Copy::class) {
+    description = "Creates a directory with the importMaven properties which can be set" +
+            " as an input directory to the java resources"
+    from(writeConfigPropsTask.map { it.outputFile })
+    into(project.layout.buildDirectory.dir("environmentConfig"))
 }
 
-/**
- * Configuration used to fetch the requested dependency's Java Runtime dependencies.
- */
-val javaRuntimeConfiguration: Configuration by configurations.creating {
-    attributes {
-        attribute(
-            LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
-            objects.named(LibraryElements.JAR)
-        )
-        attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
-
+java {
+    sourceSets {
+        main {
+            resources.srcDir(createPropertiesResourceDirectoryTask.map { it.destinationDir })
+        }
     }
-    extendsFrom(configurations.runtimeClasspath.get())
-}
-
-/**
- * Configuration used to fetch the requested dependency's Java API dependencies.
- */
-val javaApiConfiguration: Configuration by configurations.creating {
-    attributes {
-        attribute(
-            LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
-            objects.named(LibraryElements.JAR)
-        )
-        attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_API))
-
-    }
-    extendsFrom(configurations.runtimeClasspath.get())
-}
-
-/**
- * Configuration used to fetch the requested dependency's Kotlin API dependencies.
- * (klib, etc)
- */
-val kotlinApiConfiguration: Configuration by configurations.creating {
-    attributes {
-        attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage::class.java, KotlinUsages.KOTLIN_API))
-    }
-    extendsFrom(configurations.runtimeClasspath.get())
 }
 
 dependencies {
-    // We reuse the runtimeClasspath configuration provided by the java gradle plugin by
-    // extending it in our directDependencyConfiguration and allDependenciesConfiguration,
-    // so we can look up transitive closure of all the dependencies.
-    for (artifactName in artifactNames) {
-        implementation(artifactName)
-    }
-
-    // Specify to use our custom variant rule that sets up to fetch exactly the files
-    // we care about
-    components {
-        all<DirectMetadataAccessVariantRule>()
-    }
-    // Specify that both AARs and Jars are compatible
-    attributesSchema.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE)
-        .compatibilityRules.add(JarAndAarAreCompatible::class.java)
+    implementation(libs.kotlinGradlePluginz)
+    implementation(gradleTestKit())
+    implementation(libs.kotlinCoroutinesCore)
+    implementation(importMavenLibs.okio)
+    implementation(importMavenLibs.bundles.ktorServer)
+    implementation(importMavenLibs.ktorClientOkHttp)
+    implementation(importMavenLibs.clikt)
+    implementation(importMavenLibs.bundles.log4j)
+    testImplementation(kotlin("test"))
+    testImplementation(libs.junit)
+    testImplementation(libs.truth)
+    testImplementation(importMavenLibs.okioFakeFilesystem)
 }
 
-/**
- * Checks if an artifact is *internal*.
- */
-fun isInternalArtifact(artifact: ResolvedArtifactResult): Boolean {
-    val component = artifact.id.componentIdentifier as? ModuleComponentIdentifier
-    if (component != null) {
-        val group = component.group
-        for (regex in internalArtifacts) {
-            val match = regex.matches(group)
-            if (match) {
-                return true
-            }
-        }
-
-        for (regex in potentialInternalArtifacts) {
-            val matchResult = regex.matchEntire(group)
-            val match = regex.matches(group) &&
-                    matchResult?.destructured?.let { (sub) ->
-                        !forceExternal.contains(sub)
-                    } ?: true
-            if (match) {
-                return true
-            }
-        }
-    }
-    return false
+tasks.withType<KotlinCompile> {
+    kotlinOptions.jvmTarget = "11"
 }
 
-/**
- * Helps generate digests for the artifacts.
- */
-fun digest(file: File, algorithm: String): File {
-    val messageDigest = MessageDigest.getInstance(algorithm)
-    val contents = file.readBytes()
-    val digestBytes = messageDigest.digest(contents)
-    val builder = StringBuilder()
-    for (byte in digestBytes) {
-        builder.append(String.format("%02x", byte))
-    }
-    val parent = System.getProperty("java.io.tmpdir")
-    val outputFile = File(parent, "${file.name}.${algorithm.toLowerCase()}")
-    outputFile.deleteOnExit()
-    outputFile.writeText(builder.toString())
-    return outputFile
+application {
+    mainClass.set("androidx.build.importMaven.MainKt")
 }
 
-/**
- * Fetches license information for external dependencies.
- */
-fun licenseFor(pomFile: File): File? {
-    try {
-        val builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
-        val document = builder.parse(pomFile)
-        val client = OkHttpClient()
-        /*
-          This is what a licenses declaration looks like:
-          <licenses>
-            <license>
-              <name>Android Software Development Kit License</name>
-              <url>https://developer.android.com/studio/terms.html</url>
-              <distribution>repo</distribution>
-            </license>
-          </licenses>
-         */
-        val licenses = document.getElementsByTagName("license")
-        for (i in 0 until licenses.length) {
-            val license = licenses.item(i)
-            val children = license.childNodes
-            for (j in 0 until children.length) {
-                val element = children.item(j)
-                if (element.nodeName.toLowerCase() == "url") {
-                    val url = element.textContent
-                    val payload = "{\"url\": \"$url\"}".toRequestBody(mediaType)
-                    val request = Request.Builder().url(licenseEndpoint).post(payload).build()
-                    val response = client.newCall(request).execute()
-                    val contents = response.body?.string()
-                    if (contents != null) {
-                        val parent = System.getProperty("java.io.tmpdir")
-                        val outputFile = File(parent, "${pomFile.name}.LICENSE")
-                        outputFile.deleteOnExit()
-                        outputFile.writeText(contents)
-                        return outputFile
-                    }
-                }
-            }
-        }
-    } catch (exception: Throwable) {
-        println("Error fetching license information for $pomFile")
-    }
-    return null
-}
-
-/**
- * Transforms POM files so we automatically comment out nodes with <type>aar</type>.
- *
- * We are doing this for all internal libraries to account for -Pandroidx.useMaxDepVersions
- * which swaps out the dependencies of all androidx libraries with their respective ToT versions.
- * For more information look at b/127495641.
- */
-fun transformInternalPomFile(file: File): File {
-    val factory = DocumentBuilderFactory.newInstance()
-    val builder = factory.newDocumentBuilder()
-    val document = builder.parse(file)
-    document.normalizeDocument()
-
-    val container = document.getElementsByTagName("dependencies")
-    if (container.length <= 0) {
-        return file
-    }
-
-    fun findTypeAar(dependency: Node): Element? {
-        val children = dependency.childNodes
-        for (i in 0 until children.length) {
-            val node = children.item(i)
-            if (node.nodeType == Node.ELEMENT_NODE) {
-                val element = node as Element
-                if (element.tagName.toLowerCase() == "type" &&
-                    element.textContent?.toLowerCase() == "aar"
-                ) {
-                    return element
-                }
-            }
-        }
-        return null
-    }
-
-    for (i in 0 until container.length) {
-        val dependencies = container.item(i)
-        for (j in 0 until dependencies.childNodes.length) {
-            val dependency = dependencies.childNodes.item(j)
-            val element = findTypeAar(dependency)
-            if (element != null) {
-                val replacement = document.createComment("<type>aar</type>")
-                dependency.replaceChild(replacement, element)
-            }
-        }
-    }
-
-    val parent = System.getProperty("java.io.tmpdir")
-    val outputFile = File(parent, "${file.name}.transformed")
-    outputFile.deleteOnExit()
-
-    val transformer = TransformerFactory.newInstance().newTransformer()
-    val domSource = DOMSource(document)
-    val result = StreamResult(outputFile)
-    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "true")
-    transformer.setOutputProperty(OutputKeys.INDENT, "true")
-    transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8")
-    transformer.transform(domSource, result)
-    return outputFile
-}
-
-/**
- * Copies artifacts to the right locations.
- * Returns true if the artifact is copied, false if it is skipped.
- */
-fun copyArtifact(artifact: ResolvedArtifactResult, internal: Boolean = false): Boolean {
-    val folder = if (internal) internalFolder else externalFolder
-    val file = artifact.file
-    val component = artifact.id.componentIdentifier as? ModuleComponentIdentifier
-    if (component == null) {
-        println("skipping $artifact because component is null")
-        return false
-    }
-    val group = component.group
-    val moduleName = component.module
-    val moduleVersion = component.version
-    val groupPath = groupToPath(group)
-    val pathComponents = listOf(
-        prebuiltsLocation,
-        folder,
-        groupPath,
-        moduleName,
-        moduleVersion
-    )
-    val location = pathComponents.joinToString("/")
-    if (file.name.endsWith(".pom")) {
-        copyPomFile(group, moduleName, moduleVersion, file, internal)
-    } else {
-        println("Copying ${file.name} to $location")
-        copy {
-            from(
-                file,
-                digest(file, "MD5"),
-                digest(file, "SHA1")
-            )
-            rename { fileName ->
-                // see: https://issuetracker.google.com/issues/232656831#comment2
-                // klib files lose version when they are downloaded, recover it.
-                when {
-                    fileName.contains("cinterop-interop.klib") -> {
-                        "$moduleName-$moduleVersion-cinterop-interop.klib${fileName.substringAfter("cinterop-interop.klib")}"
-                    }
-                    fileName.contains(".klib") -> {
-                        "$moduleName-$moduleVersion.klib${fileName.substringAfter(".klib")}"
-                    }
-                    else -> fileName
-                }
-            }
-            into(location)
-        }
-    }
-    return true
-}
-
-/**
- * Copies associated POM files to the right location.
- */
-fun copyPomFile(
-    group: String,
-    name: String,
-    version: String,
-    pomFile: File,
-    internal: Boolean = false
-) {
-    val folder = if (internal) internalFolder else externalFolder
-    val groupPath = groupToPath(group)
-    val pathComponents = listOf(
-        prebuiltsLocation,
-        folder,
-        groupPath,
-        name,
-        version
-    )
-    val location = pathComponents.joinToString("/")
-    // Copy associated POM files.
-    val transformed = if (internal) transformInternalPomFile(pomFile) else pomFile
-    println("Copying ${pomFile.name} to $location")
-    copy {
-        from(transformed)
-        into(location)
-        rename {
-            pomFile.name
-        }
-    }
-    // Keep original MD5 and SHA1 hashes
-    copy {
-        from(
-            digest(pomFile, "MD5"),
-            digest(pomFile, "SHA1")
-        )
-        into(location)
-    }
-    // Copy licenses if available for external dependencies
-    val license = if (!internal) licenseFor(pomFile) else null
-    if (license != null) {
-        println("Copying License files for ${pomFile.name} to $location")
-        copy {
-            from(license)
-            into(location)
-            // rename to a file called LICENSE
-            rename { "LICENSE" }
-        }
-    }
-}
-
-/**
- * Given a groupId, returns a relative filepath telling where to place that group
- */
-fun groupToPath(group: String): String {
-    return if (group != "") {
-        group.split(".").joinToString("/")
-    } else {
-        "no-group"
-    }
-}
-
-/**
- * A [AttributeCompatibilityRule] that makes Gradle consider both aar and jar as compatible
- * artifacts (by default it would only want `jar` as this build.gradle.kts project is `java`)
- */
-@CacheableRule
-abstract class JarAndAarAreCompatible : AttributeCompatibilityRule<LibraryElements> {
-    override fun execute(t: CompatibilityCheckDetails<LibraryElements>) {
-        val consumer = t.consumerValue ?: return
-        val producer = t.producerValue ?: return
-
-        if (consumer.name.compareTo("jar", ignoreCase = true) == 0 &&
-                producer.name.compareTo("aar", ignoreCase = true) == 0
-            ) {
-                t.compatible()
-            } else if (consumer.name == producer.name) {
-                t.compatible()
-            }
-    }
-}
-
-/**
- * A [ComponentMetadataRule] that allows us to pick which files we want to download.
- */
-@CacheableRule
-open class DirectMetadataAccessVariantRule : ComponentMetadataRule {
-    @javax.inject.Inject
-    open fun getObjects(): ObjectFactory = throw UnsupportedOperationException()
-
-    override fun execute(ctx: ComponentMetadataContext) {
-        val id = ctx.details.id
-        ctx.details.allVariants {
-            // With files lambda is executed for every dependency in the Gradle dependency graph
-            // that was resolved using the specified attributes.
-            withFiles {
-                addFile("${id.name}-${id.version}.pom")
-                addFile("${id.name}-${id.version}.pom.asc")
-                addFile("${id.name}-${id.version}.module")
-                addFile("${id.name}-${id.version}.module.asc")
-                addFile("${id.name}-${id.version}.jar")
-                addFile("${id.name}-${id.version}.jar.asc")
-                addFile("${id.name}-${id.version}.aar")
-                addFile("${id.name}-${id.version}.aar.asc")
-                addFile("${id.name}-${id.version}-sources.jar")
-                addFile("${id.name}-${id.version}.klib")
-                addFile("${id.name}-${id.version}.klib.asc")
-                addFile("${id.name}-${id.version}-cinterop-interop.klib")
-                addFile("${id.name}-${id.version}-cinterop-interop.klib.asc")
-            }
-        }
-    }
-}
-tasks.register("fetchArtifacts") {
-    doLast {
-        var numArtifactsFound = 0
-        println("\r\nAll Files with Dependencies")
-        val copiedArtifacts = mutableSetOf<File>()
-        val kotlinConfigurationNames = kotlin.targets.flatMap { target ->
-            target.compilations.flatMap {
-                it.relatedConfigurationNames
-            }
-        } + kotlin.sourceSets.flatMap { ss ->
-            ss.relatedConfigurationNames
-        }
-        val kotlinConfigurations = kotlinConfigurationNames
-            .distinct()
-            .mapNotNull {
-                configurations.findByName(it)
-            }.filter {
-                it.isCanBeResolved
-            }
-        val targetConfigurations = kotlinConfigurations + listOf(
-            javaRuntimeConfiguration,
-            javaApiConfiguration,
-            kotlinApiConfiguration
-        )
-        targetConfigurations.forEach { configuration ->
-            configuration.incoming.artifactView {
-                // We need to be lenient because we are requesting files that might not exist.
-                // For example source.jar or .asc.
-                lenient(true)
-            }.artifacts.filter {
-                copiedArtifacts.add(it.file)
-            }.forEach {
-                if (copyArtifact(it, internal = isInternalArtifact(it))) {
-                    numArtifactsFound++
-                }
-            }
-        }
-
-        if (numArtifactsFound < 1) {
-            var message = "Artifact(s) ${artifactNames.joinToString { it }} not found!"
-            if (metalavaBuildId != null) {
-                message += "\nMake sure that ab/$metalavaBuildId contains the `metalava` "
-                message += "target and that it has finished building, or see "
-                message += "ab/metalava-master for available build ids"
-            }
-            throw GradleException(message)
-        }
-        println("\r\nResolved $numArtifactsFound artifacts for ${artifactNames.joinToString { it }}.")
-    }
-}
-
-defaultTasks("fetchArtifacts")
+tasks.named("installDist", Sync::class).configure {
+    // some jars will be duplicate, we can pick any since they are
+    // versioned.
+    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+}
\ No newline at end of file
diff --git a/development/importMaven/gradle b/development/importMaven/gradle
new file mode 120000
index 0000000..27b2e9c
--- /dev/null
+++ b/development/importMaven/gradle
@@ -0,0 +1 @@
+../../playground-common/gradle
\ No newline at end of file
diff --git a/development/importMaven/gradle.properties b/development/importMaven/gradle.properties
deleted file mode 120000
index 03ca90c..0000000
--- a/development/importMaven/gradle.properties
+++ /dev/null
@@ -1 +0,0 @@
-../../gradle.properties
\ No newline at end of file
diff --git a/development/importMaven/gradle.properties b/development/importMaven/gradle.properties
new file mode 100644
index 0000000..16363a1
--- /dev/null
+++ b/development/importMaven/gradle.properties
@@ -0,0 +1,2 @@
+kotlin.code.style=official
+org.gradle.dependency.verification=off
\ No newline at end of file
diff --git a/development/importMaven/gradlew b/development/importMaven/gradlew
index 343e0d2..d9f055c 120000
--- a/development/importMaven/gradlew
+++ b/development/importMaven/gradlew
@@ -1 +1 @@
-../../gradlew
\ No newline at end of file
+../../playground-common/gradlew
\ No newline at end of file
diff --git a/development/importMaven/importMaven.sh b/development/importMaven/importMaven.sh
new file mode 100755
index 0000000..91a8fc8
--- /dev/null
+++ b/development/importMaven/importMaven.sh
@@ -0,0 +1,9 @@
+#! /bin/bash
+# helper script to build importMaven and execute with the given arguments.
+set -e
+WORKING_DIR=`pwd`
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
+# build importMaven
+(cd $SCRIPT_DIR && ./gradlew installDist -q)
+# execute the output binary
+(SUPPORT_REPO=$SCRIPT_DIR/../.. $SCRIPT_DIR/build/install/importMaven/bin/importMaven $@)
\ No newline at end of file
diff --git a/development/importMaven/importMaven.versions.toml b/development/importMaven/importMaven.versions.toml
new file mode 100644
index 0000000..31a76dc
--- /dev/null
+++ b/development/importMaven/importMaven.versions.toml
@@ -0,0 +1,20 @@
+# extra dependencies that are used in importMaven
+
+[versions]
+okio = "3.1.0"
+ktor = "2.0.2"
+log4j = "2.17.2"
+[libraries]
+
+okio = { module = "com.squareup.okio:okio", version.ref = "okio" }
+okioFakeFilesystem = { module = "com.squareup.okio:okio-fakefilesystem", version.ref = "okio"}
+ktorServerCoreJvm = { module = "io.ktor:ktor-server-core-jvm", version.ref = "ktor" }
+ktorServerNettyJvm = { module = "io.ktor:ktor-server-netty-jvm", version.ref = "ktor" }
+ktorClientOkHttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
+clikt = { module = "com.github.ajalt.clikt:clikt", version = "3.4.2"}
+log4jApi = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j"}
+log4jCore = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j"}
+log4jKotlin = { module = "org.apache.logging.log4j:log4j-api-kotlin", version = "1.1.0" }
+[bundles]
+ktorServer = ["ktorServerCoreJvm", "ktorServerNettyJvm" ]
+log4j = ["log4jApi", "log4jCore", "log4jKotlin"]
diff --git a/development/importMaven/import_maven_artifacts.py b/development/importMaven/import_maven_artifacts.py
index 304d242..c3f6947 100755
--- a/development/importMaven/import_maven_artifacts.py
+++ b/development/importMaven/import_maven_artifacts.py
@@ -65,62 +65,25 @@
                         required=False, action='store_true')
     parse_result = parser.parse_args()
     artifact_name = parse_result.name
-    if ("kotlin-native-linux" in artifact_name or "kotlin-native-prebuilt-linux" in artifact_name):
-        artifact_name = fix_kotlin_native(artifact_name)
 
-    # Add -Dorg.gradle.debug=true to debug or --stacktrace to see the stack trace
-    command = './gradlew --build-file build.gradle.kts --no-configuration-cache -PartifactNames=%s' % (
-        artifact_name)
+    command = 'importMaven.sh %s' % (artifact_name)
     # AndroidX Build Id
     androidx_build_id = parse_result.androidx_build_id
     if (androidx_build_id):
-      command = command + ' -PandroidxBuildId=%s' % (androidx_build_id)
+      command = command + ' --androidx-build-id %s' % (androidx_build_id)
     # Metalava Build Id
     metalava_build_id = parse_result.metalava_build_id
     if (metalava_build_id):
-      command = command + ' -PmetalavaBuildId=%s' % (metalava_build_id)
+      command = command + ' --metalava-build-id %s' % (metalava_build_id)
     if (parse_result.allow_jetbrains_dev):
-      command = command + ' -PallowJetbrainsDev'
-    if (parse_result.fetch_kmp_artifacts):
-      command = command + ' -PkmpBuild=true'
-    print(command)
-    
-    process = subprocess.Popen(command,
-                               shell=True,
-                               stdin=subprocess.PIPE)
-    process.communicate()
-    assert not process.returncode
+      command = command + ' --allow-jetbrains-dev'
 
-    # TODO(b/223642687) automate the updating of signature information
-    COLOR_YELLOW="\u001B[33m"
-    COLOR_CLEAR="\u001B[0m"
-    print("")
-    print(COLOR_YELLOW + "You may also need to update signature information. See gradle/README.md" + COLOR_CLEAR)
-    print("")
-
-    # Generate our own .pom file so Gradle will use this artifact without also checking the internet.
-    # This can be removed once https://youtrack.jetbrains.com/issue/KT-35049 is resolved
-    if ("kotlin-native-linux" in artifact_name):
-      version = artifact_name.split("@")[0].split(":")[2]
-      output_file = open(f"../../../.././prebuilts/androidx/external/no-group/kotlin-native-linux/{version}/kotlin-native-linux-{version}.pom", 'w+')
-      output_file.write(f"""
-<?xml version="1.0" encoding="UTF-8"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.jetbrains.kotlin</groupId>
-  <artifactId>kotlin-native-linux</artifactId>
-  <version>{version}</version>
-  <name>kotlin-native-linux</name>
-  <url>https://download.jetbrains.com/kotlin/native/builds</url>
-</project>\n""")
-      output_file.close()
-
-#kotlin-native-linux has weird syntax requirements; needs to be :kotlin-native-linux:[email protected]
-def fix_kotlin_native(name_arg):
-  if name_arg[0]!=":": name_arg = ":"+name_arg
-  if not name_arg.endswith("@tar.gz"): name_arg += "@tar.gz"
-  return name_arg
+    my_directory = os.path.dirname(sys.argv[0])
+    sys.exit("""
+        This script is deprecated and will be removed. Please execute:
+        %s/%s
+        See %s/README.md for more details.
+    """ % (my_directory, command, my_directory))
 
 if __name__ == '__main__':
     main()
diff --git a/development/importMaven/settings.gradle.kts b/development/importMaven/settings.gradle.kts
index eaf86e3..3813656 100644
--- a/development/importMaven/settings.gradle.kts
+++ b/development/importMaven/settings.gradle.kts
@@ -1,7 +1,36 @@
+/*
+ * 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.
+ */
+
+pluginManagement {
+    repositories {
+        mavenCentral()
+        gradlePluginPortal()
+        google()
+    }
+}
+
 dependencyResolutionManagement {
+    repositories {
+        mavenCentral()
+        google()
+        gradlePluginPortal()
+    }
     versionCatalogs {
-        create("libs") {
-            from(files("../../gradle/libs.versions.toml"))
+        create("importMavenLibs") {
+            from(files("importMaven.versions.toml"))
         }
     }
 }
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/ArtifactResolver.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ArtifactResolver.kt
new file mode 100644
index 0000000..531fad3
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ArtifactResolver.kt
@@ -0,0 +1,433 @@
+/*
+ * 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.build.importMaven
+
+import androidx.build.importMaven.ArtifactResolver.resolveArtifacts
+import androidx.build.importMaven.KmpConfig.SUPPORTED_KONAN_TARGETS
+import org.apache.logging.log4j.kotlin.logger
+import org.gradle.api.Named
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.artifacts.component.ModuleComponentIdentifier
+import org.gradle.api.artifacts.dsl.RepositoryHandler
+import org.gradle.api.artifacts.result.ResolvedArtifactResult
+import org.gradle.api.attributes.Attribute
+import org.gradle.api.attributes.AttributeContainer
+import org.gradle.api.attributes.Bundling
+import org.gradle.api.attributes.Category
+import org.gradle.api.attributes.LibraryElements
+import org.gradle.api.attributes.Usage
+import org.gradle.api.attributes.java.TargetJvmEnvironment
+import org.gradle.api.attributes.java.TargetJvmVersion
+import org.gradle.api.attributes.plugin.GradlePluginApiVersion
+import org.gradle.api.internal.artifacts.verification.DependencyVerificationException
+import org.gradle.util.GradleVersion
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
+import org.jetbrains.kotlin.konan.target.KonanTarget
+import java.net.URI
+
+/**
+ * Provides functionality to resolve and download artifacts.
+ * see: [resolveArtifacts]
+ * see: [LocalMavenRepoDownloader]
+ * see: [MavenRepositoryProxy]
+ */
+internal object ArtifactResolver {
+    internal val jetbrainsRepositories = listOf(
+        "https://maven.pkg.jetbrains.space/kotlin/p/dokka/dev/",
+        "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev",
+        "https://maven.pkg.jetbrains.space/public/p/compose/dev"
+    )
+
+    internal fun createAndroidXRepo(
+        buildId: Int
+    ) = "https://androidx.dev/snapshots/builds/$buildId/artifacts/repository"
+
+    internal fun createMetalavaRepo(
+        buildId: Int
+    ) = "https://androidx.dev/metalava/builds/$buildId/artifacts/repo/m2repository"
+
+    /**
+     * Resolves given set of [artifacts].
+     *
+     * @param artifacts List of artifacts to resolve.
+     * @param additionalRepositories List of repositories in addition to mavenCentral and google
+     * @param localRepositories List of local repositories. If an artifact is found here, it won't
+     *        be downloaded.
+     * @param explicitlyFetchInheritedDependencies If set to true, each discovered dependency will
+     *        be fetched again. For instance:
+     *        artifact1:v1
+     *          artifact2:v2
+     *            artifact3:v1
+     *          artifact3:v3
+     *       If this flag is `false`, we'll only fetch artifact1:v1, artifact2:v2, artifact3:v3.
+     *       If this flag is `true`, we'll fetch `artifact3:v1` as well (because artifact2:v2
+     *       declares a dependency on it even though it is overridden by the dependency of
+     *       artifact1:v1
+     * @param downloadObserver An observer that will be notified each time a file is downloaded from
+     *        a remote repository.
+     */
+    fun resolveArtifacts(
+        artifacts: List<String>,
+        additionalRepositories: List<String> = emptyList(),
+        localRepositories: List<String> = emptyList(),
+        explicitlyFetchInheritedDependencies: Boolean = false,
+        downloadObserver: DownloadObserver?,
+    ): List<ResolvedArtifactResult> {
+        return SingleUseArtifactResolver(
+            project = ProjectService.createProject(),
+            artifacts = artifacts,
+            additionalPriorityRepositories = additionalRepositories,
+            localRepositories = localRepositories,
+            explicitlyFetchInheritedDependencies = explicitlyFetchInheritedDependencies,
+            downloadObserver = downloadObserver
+        ).resolveArtifacts()
+    }
+
+    /**
+     * see docs for [ArtifactResolver.resolveArtifacts]
+     */
+    private class SingleUseArtifactResolver(
+        private val project: Project,
+        private val artifacts: List<String>,
+        private val additionalPriorityRepositories: List<String>,
+        private val localRepositories: List<String>,
+        private val explicitlyFetchInheritedDependencies: Boolean,
+        private val downloadObserver: DownloadObserver?,
+    ) {
+        private val logger = logger("ArtifactResolver")
+        fun resolveArtifacts(): List<ResolvedArtifactResult> {
+            logger.info {
+                """
+                    Starting artifact resolution
+                    Resolving artifacts: ${artifacts.joinToString(" ")}
+                    Local repositories: ${localRepositories.joinToString(" ")}
+                    High priority repositories: ${additionalPriorityRepositories.joinToString(" ")}
+                """.trimIndent()
+            }
+            return withProxyServer(
+                downloadObserver = downloadObserver
+            ) {
+                logger.trace {
+                    "Initialized proxy servers"
+                }
+
+                project.dependencies.apply {
+                    components.all(CustomMetadataRules::class.java)
+                    attributesSchema.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE)
+                        .compatibilityRules.add(JarAndAarAreCompatible::class.java)
+                }
+                val completedComponentIds = mutableSetOf<String>()
+                val pendingComponentIds = mutableSetOf<String>().also {
+                    it.addAll(artifacts)
+                }
+                val allResolvedArtifacts = mutableSetOf<ResolvedArtifactResult>()
+                do {
+                    val dependencies = pendingComponentIds.map {
+                        project.dependencies.create(it)
+                    }
+                    val resolvedArtifacts = createConfigurationsAndResolve(dependencies)
+                    allResolvedArtifacts.addAll(resolvedArtifacts)
+                    completedComponentIds.addAll(pendingComponentIds)
+                    pendingComponentIds.clear()
+                    val newComponentIds = resolvedArtifacts.mapNotNull {
+                        (it.id.componentIdentifier as? ModuleComponentIdentifier)?.toString()
+                    }.filter {
+                        !completedComponentIds.contains(it) && pendingComponentIds.add(it)
+                    }
+                    logger.trace {
+                        "New component ids:\n${newComponentIds.joinToString("\n")}"
+                    }
+                    pendingComponentIds.addAll(newComponentIds)
+                } while (explicitlyFetchInheritedDependencies && pendingComponentIds.isNotEmpty())
+                allResolvedArtifacts.toList()
+            }.also { result ->
+                logger.info {
+                    "Resolved files: ${result.size}"
+                }
+                check(result.isNotEmpty()) {
+                    "Didn't resolve any artifacts from $artifacts"
+                }
+                result.forEach { artifact ->
+                    logger.trace {
+                        artifact.id.toString()
+                    }
+                }
+            }
+        }
+
+        /**
+         * Creates configurations with the given list of dependencies and resolves them.
+         */
+        private fun createConfigurationsAndResolve(
+            dependencies: List<Dependency>
+        ): List<ResolvedArtifactResult> {
+            val configurations = dependencies.flatMap { dep ->
+                buildList {
+                    addAll(createApiConfigurations(dep))
+                    addAll(createRuntimeConfigurations(dep))
+                    addAll(createGradlePluginConfigurations(dep))
+                    addAll(createKmpConfigurations(dep))
+                }
+            }
+            return configurations.flatMap { configuration ->
+                resolveArtifacts(configuration, disableVerificationOnFailure = true)
+            }
+        }
+
+        /**
+         * Resolves the given configuration.
+         * @param configuration The configuration to resolve
+         * @param disableVerificationOnFailure If set, this method will try to re-resolve the
+         *        configuration without dependency verification. This might be necessary if an
+         *        artifact is signed but the key is not registered in any of the public key servers.
+         */
+        private fun resolveArtifacts(
+            configuration: Configuration,
+            disableVerificationOnFailure: Boolean
+        ): Set<ResolvedArtifactResult> {
+            return try {
+                configuration.incoming.artifactView {
+                    // We need to be lenient because we are requesting files that might not exist.
+                    // For example source.jar or .asc.
+                    it.lenient(true)
+                }.artifacts.artifacts ?: emptySet()
+            } catch (verificationException: DependencyVerificationException) {
+                if (disableVerificationOnFailure) {
+                    val copy = configuration.copyRecursive().also {
+                        it.resolutionStrategy.disableDependencyVerification()
+                    }
+                    logger.warn {
+                        """
+                            Failed key verification for public servers, will retry without
+                            verification.
+                            ${verificationException.message}
+                        """.trimIndent()
+                    }
+                    resolveArtifacts(copy, disableVerificationOnFailure = false)
+                } else {
+                    throw verificationException
+                }
+            }
+        }
+
+        /**
+         * Creates proxy servers for remote repositories, adds them to the project and invokes
+         * the block. Once the block is complete, all proxy servers will be closed.
+         */
+        private fun <T> withProxyServer(
+            downloadObserver: DownloadObserver? = null,
+            block: () -> T
+        ): T {
+            val repoUrls = additionalPriorityRepositories + listOf(
+                RepositoryHandler.GOOGLE_URL,
+                RepositoryHandler.MAVEN_CENTRAL_URL,
+            )
+            return MavenRepositoryProxy.startAll(
+                repositoryUrls = repoUrls,
+                downloadObserver = downloadObserver
+            ) { repoUris ->
+                project.repositories.clear()
+                // add local repositories first, they are not tracked
+                localRepositories.map { localRepo ->
+                    project.repositories.maven {
+                        it.url = URI(localRepo)
+                    }
+                }
+                repoUris.map { mavenUri ->
+                    project.repositories.maven {
+                        it.url = mavenUri
+                        it.isAllowInsecureProtocol = true
+                    }
+                }
+                block()
+            }
+        }
+
+        private fun createConfiguration(
+            vararg dependencies: Dependency,
+            configure: Configuration.() -> Unit
+        ): Configuration {
+            val configuration = project.configurations.detachedConfiguration(*dependencies)
+            configuration.configure()
+            return configuration
+        }
+
+        /**
+         * Creates a configuration that has the same attributes as java runtime configuration
+         */
+        private fun createRuntimeConfigurations(
+            vararg dependencies: Dependency
+        ): List<Configuration> {
+            return listOf(
+                LibraryElements.JAR,
+                "aar"
+            ).map { libraryElement ->
+                createConfiguration(*dependencies) {
+                    attributes.apply {
+                        attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, libraryElement)
+                        attribute(Usage.USAGE_ATTRIBUTE, Usage.JAVA_RUNTIME)
+                        attribute(Category.CATEGORY_ATTRIBUTE, Category.LIBRARY)
+                        attribute(Bundling.BUNDLING_ATTRIBUTE, Bundling.EXTERNAL)
+                    }
+                }
+            }
+        }
+
+        @Suppress("UnstableApiUsage")
+        private fun createGradlePluginConfigurations(
+            vararg dependencies: Dependency
+        ): List<Configuration> {
+            return listOf(
+                GradleVersion.current().baseVersion,
+                GradleVersion.current()
+            ).map { version ->
+                // taken from DefaultScriptHandler in gradle
+                createConfiguration(*dependencies) {
+                    attributes.apply {
+                        attribute(Category.CATEGORY_ATTRIBUTE, Category.LIBRARY)
+                        attribute(Bundling.BUNDLING_ATTRIBUTE, Bundling.EXTERNAL)
+                        attribute(
+                            TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
+                            TargetJvmEnvironment.STANDARD_JVM
+                        )
+
+                        attribute(Usage.USAGE_ATTRIBUTE, Usage.JAVA_API)
+
+                        attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, LibraryElements.JAR)
+
+                        attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 8)
+                        attribute(
+                            GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE,
+                            version.version
+                        )
+                    }
+                }
+            }
+        }
+
+        /**
+         * Creates a configuration that has the same attributes as java api configuration
+         */
+        private fun createApiConfigurations(
+            vararg dependencies: Dependency
+        ): List<Configuration> {
+            return listOf(
+                LibraryElements.JAR,
+                "aar"
+            ).map { libraryElement ->
+                createConfiguration(*dependencies) {
+                    attributes.apply {
+                        attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, libraryElement)
+                        attribute(Usage.USAGE_ATTRIBUTE, Usage.JAVA_API)
+                        attribute(Category.CATEGORY_ATTRIBUTE, Category.LIBRARY)
+                        attribute(Bundling.BUNDLING_ATTRIBUTE, Bundling.EXTERNAL)
+                    }
+                }
+            }
+        }
+
+        /**
+         * Creates configuration that resembles the ones created by KMP.
+         * Note that, the configurations built by KMP depends on flags etc so to account for all of
+         * them, we create all variations with different attribute values.
+         */
+        private fun createKmpConfigurations(
+            vararg dependencies: Dependency,
+        ): List<Configuration> {
+            val konanTargetConfigurations = SUPPORTED_KONAN_TARGETS.flatMap { konanTarget ->
+                KOTlIN_USAGES.map { kotlinUsage ->
+                    createKonanTargetConfiguration(
+                        dependencies = dependencies,
+                        konanTarget = konanTarget,
+                        kotlinUsage = kotlinUsage
+                    )
+                }
+            }
+            // jvm and android configurations
+            val jvmAndAndroid = KOTlIN_USAGES.flatMap { kotlinUsage ->
+                listOf(
+                    "jvm",
+                    TargetJvmEnvironment.ANDROID
+                ).map { targetJvm ->
+                    createConfiguration(*dependencies) {
+                        attributes.apply {
+                            attribute(Usage.USAGE_ATTRIBUTE, kotlinUsage)
+                            attribute(Category.CATEGORY_ATTRIBUTE, Category.LIBRARY)
+                            attribute(
+                                TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
+                                targetJvm
+                            )
+                        }
+                    }
+                }
+            }
+            val commonArtifacts = KOTlIN_USAGES.map { kotlinUsage ->
+                createConfiguration(*dependencies) {
+                    attributes.apply {
+                        attribute(Usage.USAGE_ATTRIBUTE, kotlinUsage)
+                        attribute(Category.CATEGORY_ATTRIBUTE, Category.LIBRARY)
+                        attribute(KotlinPlatformType.attribute, KotlinPlatformType.common)
+                    }
+                }
+            }
+            return jvmAndAndroid + konanTargetConfigurations + commonArtifacts
+        }
+
+        private fun createKonanTargetConfiguration(
+            vararg dependencies: Dependency,
+            konanTarget: KonanTarget,
+            kotlinUsage: String
+        ): Configuration {
+            return createConfiguration(*dependencies) {
+                attributes.apply {
+                    attribute(KotlinPlatformType.attribute, KotlinPlatformType.native)
+                    attribute(Usage.USAGE_ATTRIBUTE, kotlinUsage)
+                    attribute(KotlinNativeTarget.konanTargetAttribute, konanTarget.name)
+                    attribute(Category.CATEGORY_ATTRIBUTE, Category.LIBRARY)
+                    attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, "non-jvm")
+                }
+            }
+        }
+
+        private fun <T : Named> AttributeContainer.attribute(
+            key: Attribute<T>,
+            value: String
+        ) = attribute(
+            key, project.objects.named(
+                key.type,
+                value
+            )
+        )
+
+        companion object {
+            /**
+             * Kotlin usage attributes that we want to pull.
+             */
+            private val KOTlIN_USAGES = listOf(
+                KotlinUsages.KOTLIN_API,
+                KotlinUsages.KOTLIN_METADATA,
+                KotlinUsages.KOTLIN_CINTEROP,
+                KotlinUsages.KOTLIN_RUNTIME,
+                KotlinUsages.KOTLIN_SOURCES
+            )
+        }
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/CustomMetadataRules.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/CustomMetadataRules.kt
new file mode 100644
index 0000000..bece7c4
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/CustomMetadataRules.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.build.importMaven
+
+import org.gradle.api.artifacts.ComponentMetadataContext
+import org.gradle.api.artifacts.ComponentMetadataRule
+
+/**
+ * Some artifacts don't get resolved via configuration attributes.
+ * e.g. sources:
+ *   https://github.com/gradle/gradle/commit/94b266dc50b5fd7dd5460d6d32ff66eab3740627
+ *
+ * We use this ComponentMetadataRule to add them.
+ */
+class CustomMetadataRules : ComponentMetadataRule {
+    override fun execute(context: ComponentMetadataContext) {
+        val id = context.details.id
+        context.details.allVariants { variantMetadata ->
+            variantMetadata.withFiles {
+                // sources do not always get resolved for nested dependencies
+                it.addFile("${id.name}-${id.version}-sources.jar")
+                // if it does not have gradle metadata, we might miss aar; add it
+                it.addFile("${id.name}-${id.version}.aar")
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/DownloadObserver.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/DownloadObserver.kt
new file mode 100644
index 0000000..9e67d36
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/DownloadObserver.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.build.importMaven
+
+/**
+ * Interface that gets notified each time a file is downloaded from an artifactory.
+ *
+ * @see LocalMavenRepoDownloader
+ */
+fun interface DownloadObserver {
+    /**
+     * Called when a file is downloaded from an artifactory.
+     *
+     * @param path The path of the file relative to the artifactory URL
+     * @param bytes The contents of the file
+     */
+    fun onDownload(path: String, bytes: ByteArray)
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/EnvironmentConfig.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/EnvironmentConfig.kt
new file mode 100644
index 0000000..adfd43a
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/EnvironmentConfig.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.build.importMaven
+
+import okio.Path
+import okio.Path.Companion.toOkioPath
+import java.io.File
+import java.util.Properties
+
+/**
+ * Helper class to laod some environment related configuration.
+ */
+object EnvironmentConfig {
+    private val config: Properties by lazy {
+        val config = Properties()
+        val resourceName = "/importMavenConfig.properties"
+        EnvironmentConfig::class.java.getResource(resourceName).let {
+            checkNotNull(it) {
+                "Cannot find properties file: $resourceName"
+            }
+        }.openStream()
+            .use {
+                config.load(it)
+            }
+        config
+    }
+
+    /**
+     * The path for the support root folder (frameworks/support)
+     */
+    val supportRoot: Path by lazy {
+        checkNotNull(config["supportRoot"]) {
+            "missing supportRoot property"
+        }.let {
+            File(it.toString()).toOkioPath()
+        }
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/GithubLicenseApiClient.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/GithubLicenseApiClient.kt
new file mode 100644
index 0000000..f624840
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/GithubLicenseApiClient.kt
@@ -0,0 +1,75 @@
+/*
+ * 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.build.importMaven
+
+import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import org.apache.logging.log4j.kotlin.logger
+import org.jetbrains.kotlin.com.google.common.annotations.VisibleForTesting
+
+/**
+ * Downloads the license for a given Github project URL.
+ */
+class GithubLicenseApiClient {
+    private val logger = logger("GithubLicenseApiClient")
+    private val client = OkHttpClient()
+
+    /**
+     * Returns the license for the given [githubUrl] if it is a Github url and the project has a
+     * license file.
+     */
+    fun getProjectLicense(githubUrl: String): String? {
+        val (owner, repo) = githubUrl.extractGithubOwnerAndRepo() ?: return null
+        logger.trace {
+            "Getting license for $githubUrl"
+        }
+        val request = Request.Builder().url(
+            "https://api.github.com/repos/$owner/$repo/license"
+        ).addHeader(
+            "Accept", "application/vnd.github.v3.raw"
+        ).build()
+        val response = client.newCall(request).execute()
+        if (response.code == 404) {
+            logger.warn {
+                """
+                Failed to get license from github for $githubUrl
+                API response: ${response.body?.string()}
+                """.trimIndent()
+            }
+            return null
+        }
+        return response.body?.use {
+            it.string()
+        }
+    }
+
+    @VisibleForTesting
+    internal fun String.extractGithubOwnerAndRepo(): Pair<String, String>? {
+        val httpUrl = this.toHttpUrlOrNull() ?: return null
+        httpUrl.host.split('.').let {
+            if (it.size < 2) return null
+            if (it.last() != "com") return null
+            if (it[it.size - 2] != "github") return null
+        }
+        val pathSegments = httpUrl.pathSegments.filter { it.isNotBlank() }
+        if (pathSegments.size != 2) {
+            return null
+        }
+        return pathSegments[0] to pathSegments[1]
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/ImportVersionCatalog.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ImportVersionCatalog.kt
new file mode 100644
index 0000000..93a8175
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ImportVersionCatalog.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.build.importMaven
+
+import okio.FileSystem
+import okio.Path
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.internal.catalog.parser.TomlCatalogFileParser
+import org.gradle.api.plugins.catalog.VersionCatalogPlugin.GRADLE_PLATFORM_DEPENDENCIES
+import org.gradle.api.plugins.catalog.internal.DependenciesAwareVersionCatalogBuilder
+import org.gradle.internal.impldep.com.google.common.collect.Interners
+
+/**
+ * Loads all versions from a version catalog file.
+ * see [ImportToml].
+ */
+object ImportVersionCatalog {
+    /**
+     * Loads a gradle version file and returns all artifacts declared in it.
+     */
+    fun load(fileSystem: FileSystem, file: Path): List<String> {
+        val project = ProjectService.createProject()
+        val configurations = project.configurations.create(
+            GRADLE_PLATFORM_DEPENDENCIES
+        ) { cnf: Configuration ->
+            cnf.isVisible = false
+            cnf.isCanBeConsumed = false
+            cnf.isCanBeResolved = false
+        }
+        val catalogBuilder = DependenciesAwareVersionCatalogBuilder(
+            "loader",
+            Interners.newStrongInterner(),
+            Interners.newStrongInterner(),
+            project.objects,
+            project.providers,
+            { error("Not supported") },
+            configurations
+        )
+        fileSystem.read(file) {
+            TomlCatalogFileParser.parse(
+                this.inputStream(),
+                catalogBuilder
+            )
+        }
+        val built = catalogBuilder.build()
+        return built.libraryAliases.map { alias ->
+            val dep = built.getDependencyData(alias)
+            "${dep.group}:${dep.name}:${dep.version.requiredVersion}"
+        }
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/JarAndAarAreCompatible.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/JarAndAarAreCompatible.kt
new file mode 100644
index 0000000..fc8af8e
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/JarAndAarAreCompatible.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.build.importMaven
+
+import org.gradle.api.artifacts.CacheableRule
+import org.gradle.api.attributes.AttributeCompatibilityRule
+import org.gradle.api.attributes.CompatibilityCheckDetails
+import org.gradle.api.attributes.LibraryElements
+
+/**
+ * A [AttributeCompatibilityRule] that makes Gradle consider both aar and jar as compatible
+ * artifacts.
+ */
+@CacheableRule
+abstract class JarAndAarAreCompatible : AttributeCompatibilityRule<LibraryElements> {
+    override fun execute(t: CompatibilityCheckDetails<LibraryElements>) {
+        val consumer = t.consumerValue?.name ?: return
+        val producer = t.producerValue?.name ?: return
+        if (consumer.isAarOrJar() && producer.isAarOrJar()) {
+            t.compatible()
+        }
+    }
+
+    private fun String.isAarOrJar() = compareTo("jar", ignoreCase = true) == 0 ||
+            compareTo("aar", ignoreCase = true) == 0
+}
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/KmpConfig.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/KmpConfig.kt
new file mode 100644
index 0000000..693c6f0
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/KmpConfig.kt
@@ -0,0 +1,32 @@
+package androidx.build.importMaven
+
+import org.jetbrains.kotlin.konan.target.KonanTarget
+
+/**
+ * Common configuration for KMP builds.
+ */
+internal object KmpConfig {
+    /**
+     * host machines where we support compiling KMP
+     */
+    val SUPPORTED_HOSTS = listOf(
+        KonanTarget.LINUX_X64,
+        KonanTarget.MACOS_ARM64,
+        KonanTarget.MACOS_X64,
+    )
+
+    /**
+     * Supported konan targets
+     */
+    val SUPPORTED_KONAN_TARGETS = listOf(
+        KonanTarget.MACOS_ARM64,
+        KonanTarget.MACOS_X64,
+        KonanTarget.LINUX_ARM64,
+        KonanTarget.LINUX_X64,
+        KonanTarget.MINGW_X64,
+        KonanTarget.MINGW_X86,
+        KonanTarget.IOS_ARM64,
+        KonanTarget.IOS_SIMULATOR_ARM64,
+        KonanTarget.IOS_X64,
+    )
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/KonanPrebuiltsDownloader.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/KonanPrebuiltsDownloader.kt
new file mode 100644
index 0000000..826e9f6
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/KonanPrebuiltsDownloader.kt
@@ -0,0 +1,276 @@
+/*
+ * 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.build.importMaven
+
+import androidx.build.importMaven.KmpConfig.SUPPORTED_HOSTS
+import androidx.build.importMaven.KmpConfig.SUPPORTED_KONAN_TARGETS
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.runBlocking
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.internal.closeQuietly
+import okio.FileSystem
+import okio.Path
+import org.apache.logging.log4j.kotlin.logger
+import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
+import org.jetbrains.kotlin.konan.CompilerVersion.Companion.fromString
+import org.jetbrains.kotlin.konan.properties.resolvablePropertyList
+import org.jetbrains.kotlin.konan.properties.resolvablePropertyString
+import org.jetbrains.kotlin.konan.target.Architecture
+import org.jetbrains.kotlin.konan.target.Distribution
+import org.jetbrains.kotlin.konan.target.Family
+import org.jetbrains.kotlin.konan.target.HostManager
+import java.util.Properties
+
+typealias KonanProperties = org.jetbrains.kotlin.konan.properties.Properties
+
+/**
+ * Utility class to download all konan prebuilts that are required to compile native code.
+ * These files are often downloaded into `/prebuilts/androidx/konan`.
+ */
+class KonanPrebuiltsDownloader(
+    private val fileSystem: FileSystem,
+    private val downloadPath: Path,
+    private val testMode: Boolean = false
+) {
+    private val logger = logger("KonanPrebuiltsDownloader")
+    private val client = OkHttpClient()
+    fun download(
+        compilerVersion: String
+    ) {
+        val project = ProjectService.createProject()
+        val compiler = NativeCompilerDownloader(
+            project = project,
+            compilerVersion = fromString(compilerVersion)
+        )
+        // make sure we have the local compiler downloaded so we can find the konan.properties
+        compiler.downloadIfNeeded()
+        val distribution = Distribution(compiler.compilerDirectory.canonicalPath)
+        // base konan properties file for reference:
+        // https://github.com/JetBrains/kotlin/blob/master/kotlin-native/konan/konan.properties
+        // Note that [Distribution] might add overrides.
+        val compilationDependencies = findCompilationDependencies(
+            konanProperties = distribution.properties
+        )
+        downloadDistributions(compilationDependencies)
+        // for linux x64 we need to provide the up-to-date sysroot, hence, update the config file
+        // with the kotlinVersion -> sysroot zip file.
+        updateSysrootFile(distribution.properties)
+        downloadNativeCompiler(compilerVersion)
+    }
+
+    private fun downloadNativeCompiler(
+        compilerVersion: String
+    ) {
+        SUPPORTED_HOSTS.forEach { host ->
+            HostManager.simpleOsName()
+            val osName = when (host.family) {
+                Family.OSX -> "macos"
+                Family.LINUX -> "linux"
+                else -> "unsupported host family: $host"
+            }
+            val archName = when (host.architecture) {
+                Architecture.X64 -> "x86_64"
+                Architecture.ARM64 -> "aarch64"
+                else -> "unsupported architecture: $host"
+            }
+            val platformName = "$osName-$archName"
+            val subPath = listOf(
+                "releases",
+                compilerVersion,
+                platformName,
+                "kotlin-native-prebuilt-$platformName-$compilerVersion.tar.gz"
+            ).joinToString("/")
+            val url = listOf(
+                NATIVE_COMPILERS_BASE_URL,
+                subPath
+            ).joinToString("/")
+            downloadIfNecessary(
+                url = url,
+                localFile = downloadPath / "nativeCompilerPrebuilts" / subPath
+            )
+        }
+    }
+
+    private fun updateSysrootFile(properties: KonanProperties) {
+        val sysrootFile = downloadPath / "linux-prebuilts.properties"
+        val sysrootProps = Properties()
+        if (fileSystem.exists(sysrootFile)) {
+            fileSystem.read(sysrootFile) {
+                sysrootProps.load(
+                    this.inputStream()
+                )
+            }
+        }
+        val compilerVersion = properties.requireResolvablePropertyString("compilerVersion")
+        val gccLinuxToolchain = properties.requireResolvablePropertyString("gccToolchain.linux_x64")
+        sysrootProps.setProperty(
+            compilerVersion,
+            gccLinuxToolchain
+        )
+        fileSystem.write(sysrootFile) {
+            // write manually to avoid the timestamp
+            sysrootProps.forEach { key, value ->
+                this.writeString("$key=$value\n", Charsets.UTF_8)
+            }
+        }
+    }
+
+    private fun Properties.requireResolvablePropertyString(key: String) =
+        checkNotNull(resolvablePropertyString(key)) {
+            val allProperties = this.keys.sortedBy { it.toString() }.joinToString("\n")
+            "Cannot find required key : $key. Available properties:\n $allProperties"
+        }
+
+    /**
+     * Finds the compilation dependencies of each supported host machine.
+     *
+     * There are 3 groups of distributions we need to compile offline:
+     * * llvm -> needed for all targets (host based)
+     *   llvm.<host>.user
+     * * ffi -> needed for all targets (host based)
+     *   llvm.<host>
+     * * target specific dependencies (host + target combinations)
+     *   dependencies.<host>(-<target>)?
+     *
+     * Technically, a host machine might be capable of building for multiple targets. For instance,
+     * macOS can build for windows. To avoid excessive downloads, we only download artifacts that
+     * are in the [SUPPORTED_TARGETS] lists.
+     */
+    private fun findCompilationDependencies(konanProperties: KonanProperties): List<String> {
+        val hostDeps = SUPPORTED_HOST_NAMES.flatMap { host ->
+            listOf("llvm.$host.user", "libffiDir.$host")
+        }
+        val dependencies = buildHostAndTargetKeys("dependencies")
+        val gccDeps = SUPPORTED_HOST_NAMES.flatMap { host ->
+            listOf("gccToolchain.$host")
+        }
+        return (hostDeps + dependencies + gccDeps).flatMap {
+            konanProperties.resolvablePropertyList(it)
+        }.distinct()
+    }
+
+    private fun buildHostAndTargetKeys(prefix: String): List<String> {
+        return SUPPORTED_HOST_NAMES.flatMap { host ->
+            listOf(
+                "$prefix.$host"
+            ) + SUPPORTED_TARGETS.map { target ->
+                "$prefix.$host-$target"
+            }
+        }
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    private fun downloadDistributions(
+        distributions: List<String>
+    ) {
+        runBlocking(Dispatchers.IO.limitedParallelism(4)) {
+            val results = distributions.map { dist ->
+                // since we always build on linux/mac, we use the tar.gz artifacts.
+                // if we ever add support for windows builds, we would need to use zip.
+                val fileName = "$dist.tar.gz"
+                val localFile = downloadPath / fileName
+                async {
+                    val url = "$REPO_BASE_URL/$fileName"
+                    url to runCatching {
+                        downloadIfNecessary(
+                            url = url,
+                            localFile = localFile
+                        )
+                    }
+                }
+            }.awaitAll()
+            val failures = results.filter { it.second.isFailure }
+            if (failures.isNotEmpty()) {
+                error(buildString {
+                    appendLine("Couldn't fetch ${failures.size} of ${results.size} artifacts")
+                    appendLine("Failed artifacts:")
+                    failures.forEach { failure ->
+                        appendLine("${failure.first}:")
+                        appendLine(failure.second.exceptionOrNull()!!.stackTraceToString())
+                        appendLine("----")
+                    }
+                })
+            }
+        }
+    }
+
+    /**
+     * Downloads a url into [localFile] if it does not already exists.
+     */
+    private fun downloadIfNecessary(
+        url: String,
+        localFile: Path
+    ) {
+        if (fileSystem.exists(localFile)) {
+            logger.trace {
+                "${localFile.name} exists, won't re-download"
+            }
+        } else {
+            logger.trace {
+                "will download $url into $localFile"
+            }
+            val tmpFile = localFile.parent!! / "${localFile.name}.tmp"
+            if (fileSystem.exists(tmpFile)) {
+                fileSystem.delete(tmpFile)
+            }
+            val response = client.newCall(Request.Builder().url(url).build()).execute()
+            try {
+                check(response.isSuccessful) {
+                    "Failed to fetch $url"
+                }
+                fileSystem.createDirectories(localFile.parent!!)
+                checkNotNull(response.body?.source()) {
+                    "No body while fetching $url"
+                }.use { bodySource ->
+                    fileSystem.write(
+                        file = tmpFile,
+                        mustCreate = true
+                    ) {
+                        if (testMode) {
+                            // don't download the whole file for tests
+                            this.write(bodySource.readByteArray(10))
+                        } else {
+                            this.writeAll(bodySource)
+                        }
+                    }
+                }
+                response.body?.close()
+                fileSystem.atomicMove(source = tmpFile, target = localFile)
+                logger.trace {
+                    "Finished downloading $url into $localFile"
+                }
+            } finally {
+                response.closeQuietly()
+            }
+        }
+    }
+
+    companion object {
+        private const val REPO_BASE_URL = "https://download.jetbrains.com/kotlin/native"
+        private const val NATIVE_COMPILERS_BASE_URL = "$REPO_BASE_URL/builds"
+
+        private val SUPPORTED_HOST_NAMES = SUPPORTED_HOSTS.map { it.name }
+
+        // target architectures for which we might build artifacts for.
+        private val SUPPORTED_TARGETS =
+            SUPPORTED_HOST_NAMES + SUPPORTED_KONAN_TARGETS.map { it.name }
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/LicenseDownloader.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/LicenseDownloader.kt
new file mode 100644
index 0000000..e4a8b36
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/LicenseDownloader.kt
@@ -0,0 +1,116 @@
+/*
+ * 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.build.importMaven
+
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody.Companion.toRequestBody
+import org.apache.logging.log4j.kotlin.logger
+import org.w3c.dom.Node
+import javax.xml.parsers.DocumentBuilderFactory
+import javax.xml.xpath.XPathConstants
+import javax.xml.xpath.XPathFactory
+
+/**
+ * Pulls the license for a given project.
+ * A license might be fetched:
+ * * directly, if it is a txt url
+ * * from github, if it is a github project
+ * * via license server, as the fallback.
+ */
+class LicenseDownloader(
+    /**
+     * If set, we'll also query github API to get the license.
+     * Note that, even though this provides better license files, it might potentially fetch the
+     * wrong license if the project changed its license.
+     */
+    private val enableGithubApi: Boolean = false
+) {
+    private val logger = logger("LicenseDownloader")
+    private val mediaType = "application/json; charset=utf-8".toMediaType()
+    private val licenseEndpoint = "https://fetch-licenses.appspot.com/convert/licenses"
+    private val githubLicenseApiClient = GithubLicenseApiClient()
+    private val licenseXPath = XPathFactory.newInstance().newXPath()
+        .compile("/project/licenses/license/url")
+    private val scmUrlXPath = XPathFactory.newInstance().newXPath()
+        .compile("/project/scm/url")
+    private val client = OkHttpClient()
+
+    /**
+     * Fetches license information for external dependencies.
+     */
+    fun fetchLicenseFromPom(bytes: ByteArray): ByteArray? {
+        val builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+        val document = bytes.inputStream().use {
+            builder.parse(it)
+        }
+        val licenseUrl = (licenseXPath.evaluate(document, XPathConstants.NODE) as? Node)
+            ?.textContent
+        val scmUrl = (scmUrlXPath.evaluate(document, XPathConstants.NODE) as? Node)?.textContent
+        val fetchers = listOf(
+            {
+                // directly download if it is a txt file
+                licenseUrl?.let(this::tryFetchTxtLicense)
+            },
+            {
+                // download via github API if it is hosted on github
+                if (enableGithubApi) {
+                    scmUrl?.let(githubLicenseApiClient::getProjectLicense)
+                } else {
+                    null
+                }
+            },
+            {
+                // fallback to license server
+                licenseUrl?.let(this::fetchViaLicenseProxy)
+            }
+        )
+        val licenseContents = fetchers.firstNotNullOfOrNull {
+            it()
+        } ?: return null
+        // get rid of any windows style line endings or extra newlines
+        val cleanedUp = licenseContents.replace("\r", "").dropLastWhile {
+            it == '\n'
+        } + "\n"
+        return cleanedUp.toByteArray(Charsets.UTF_8)
+    }
+
+    private fun tryFetchTxtLicense(url: String): String? {
+        if (!url.endsWith(".txt")) {
+            return null
+        }
+        logger.trace {
+            "Fetching license directly from $url"
+        }
+        val request = Request.Builder().url(url).build()
+        return client.newCall(request).execute().use {
+            it.body?.string()
+        }
+    }
+
+    private fun fetchViaLicenseProxy(url: String): String? {
+        logger.trace {
+            "Fetching license ($url) via license server"
+        }
+        val payload = "{\"url\": \"$url\"}".toRequestBody(mediaType)
+        val request = Request.Builder().url(licenseEndpoint).post(payload).build()
+        return client.newCall(request).execute().use {
+            it.body?.string()
+        }
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/LocalMavenRepoDownloader.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/LocalMavenRepoDownloader.kt
new file mode 100644
index 0000000..ea9fce1
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/LocalMavenRepoDownloader.kt
@@ -0,0 +1,258 @@
+/*
+ * 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.build.importMaven
+
+import okio.FileSystem
+import okio.Path
+import org.apache.logging.log4j.kotlin.logger
+import org.jetbrains.kotlin.com.google.common.annotations.VisibleForTesting
+import java.security.MessageDigest
+import java.util.Locale
+
+/**
+ * A [DownloadObserver] that will save all files into the given repository folders.
+ */
+class LocalMavenRepoDownloader(
+    val fileSystem: FileSystem,
+    /**
+     * Path to the internal repo (e.g. prebuilts/androidx/internal)
+     */
+    val internalFolder: Path,
+    /**
+     * Path to the external repo (e.g. prebuilts/androidx/external)
+     */
+    val externalFolder: Path
+) : DownloadObserver {
+    private val logger = logger("LocalMavenRepoDownloader")
+    private val licenseDownloader = LicenseDownloader(enableGithubApi = false)
+    private val writtenFiles = mutableSetOf<Path>()
+
+    /**
+     * Returns the list of files we've downloaded.
+     */
+    fun getDownloadedFiles() = writtenFiles.sorted().distinct()
+
+    override fun onDownload(path: String, bytes: ByteArray) {
+        if (path.substringAfterLast('.') in checksumExtensions) {
+            // we sign files locally, don't download them
+            logger.trace {
+                "Skipping $path because we'll sign it locally"
+            }
+            return
+        }
+        val internal = isInternalArtifact(path)
+        val folder = if (internal) internalFolder else externalFolder
+        logger.trace {
+            "Downloading $path. internal? $internal"
+        }
+        folder.resolve(path).let { file ->
+            val targetFolder = file.parent ?: error("invalid parent for $file")
+            if (file.name.endsWith(".pom")) {
+                // Keep original MD5 and SHA1 hashes
+                copyWithDigest(targetFolder, fileName = file.name, bytes = bytes)
+                if (internal) {
+                    val transformed = transformInternalPomFile(bytes)
+                    copyWithoutDigest(targetFolder, fileName = file.name, bytes = transformed)
+                } else {
+                    // download licenses only for external poms
+                    licenseDownloader.fetchLicenseFromPom(bytes)?.let { licenseBytes ->
+                        copyWithoutDigest(targetFolder, "LICENSE", licenseBytes)
+                    }
+                }
+            } else {
+                copyWithDigest(
+                    targetFolder = targetFolder,
+                    fileName = file.name,
+                    bytes = bytes
+                )
+            }
+        }
+    }
+
+    /**
+     * Creates the file in the given [targetFolder]/[fileName] pair.
+     */
+    private fun copyWithoutDigest(
+        targetFolder: Path,
+        fileName: String,
+        bytes: ByteArray
+    ) {
+        fileSystem.writeBytes(targetFolder / fileName, bytes)
+    }
+
+    /**
+     *  Creates the file in the given [targetFolder]/[fileName] pair and also creates the md5 and
+     *  sha1 checksums.
+     */
+    private fun copyWithDigest(
+        targetFolder: Path,
+        fileName: String,
+        bytes: ByteArray
+    ) {
+        copyWithoutDigest(targetFolder, fileName, bytes)
+        if (fileName.substringAfterLast('.') !in checksumExtensions) {
+            digest(bytes, fileName, "MD5").let { (name, contents) ->
+                fileSystem.writeBytes(targetFolder / name, contents)
+            }
+            digest(bytes, fileName, "SHA1").let { (name, contents) ->
+                fileSystem.writeBytes(targetFolder / name, contents)
+            }
+        }
+    }
+
+    private fun FileSystem.writeBytes(
+        file: Path,
+        contents: ByteArray
+    ) {
+        writtenFiles.add(file.normalized())
+        file.parent?.let(fileSystem::createDirectories)
+        write(
+            file = file,
+            mustCreate = false
+        ) {
+            write(contents)
+        }
+        logger.info {
+            "Saved $file (${contents.size} bytes)"
+        }
+    }
+
+    /**
+     * Certain prebuilts might have improper downloads.
+     * This method traverses all folders into which we've fetched an artifact and deletes files
+     * that are not fetched by us.
+     *
+     * Note that, sometimes we might pull a pom file but not download its artifacts (if there is a
+     * newer version). So before cleaning any file, we make sure we fetched one of
+     * [EXTENSIONS_FOR_CLENAUP].
+     *
+     * This should be used only if the local repositories are disabled in resolution. Otherwise, it
+     * might delete files that were resolved from the local repository.
+     */
+    fun cleanupLocalRepositories() {
+        val folders = writtenFiles.filter {
+            val isDirectory = fileSystem.metadata(it).isDirectory
+            !isDirectory && it.name.substringAfterLast(".") in EXTENSIONS_FOR_CLENAUP
+        }.mapNotNull {
+            it.parent
+        }.distinct()
+        logger.info {
+            "Cleaning up local repository. Folders to clean: ${folders.size}"
+        }
+
+        // traverse all folders and make sure they are in the written files list
+        folders.forEachIndexed { index, folder ->
+            logger.trace {
+                "Cleaning up $folder ($index of ${folders.size})"
+            }
+            fileSystem.list(folder).forEach { candidateToDelete ->
+                if (!writtenFiles.contains(candidateToDelete.normalized())) {
+                    logger.trace {
+                        "Deleting $candidateToDelete since it is not re-downloaded"
+                    }
+                    fileSystem.delete(candidateToDelete)
+                } else {
+                    logger.trace {
+                        "Keeping $candidateToDelete"
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Transforms POM files so we automatically comment out nodes with <type>aar</type>.
+     *
+     * We are doing this for all internal libraries to account for -Pandroidx.useMaxDepVersions
+     * which swaps out the dependencies of all androidx libraries with their respective ToT
+     * versions. For more information look at b/127495641.
+     *
+     * Instead of parsing the dom and re-writing it, we use a simple string replace to keep the file
+     * contents intact.
+     */
+    private fun transformInternalPomFile(bytes: ByteArray): ByteArray {
+        // using a simple line match rather than xml parsing because we want to keep file same as
+        // much as possible
+        return bytes.toString(Charsets.UTF_8).lineSequence().map {
+            it.replace("<type>aar</type>", "<!--<type>aar</type>-->")
+        }.joinToString("\n").toByteArray(Charsets.UTF_8)
+    }
+
+    companion object {
+        val checksumExtensions = listOf("md5", "sha1")
+
+        /**
+         * If we downloaded an artifact with one of these extensions, we can cleanup that folder
+         * for files that are not re-downloaded.
+         */
+        private val EXTENSIONS_FOR_CLENAUP = listOf(
+            "jar",
+            "aar",
+            "klib"
+        )
+        private val INTERNAL_ARTIFACT_PREFIXES = listOf(
+            "android/arch",
+            "com/android/support",
+            "androidx"
+        )
+
+        // Need to exclude androidx.databinding
+        private val FORCE_EXTERNAL_PREFIXES = setOf(
+            "androidx/databinding"
+        )
+
+        /**
+         * Checks if an artifact is *internal*.
+         */
+        fun isInternalArtifact(path: String): Boolean {
+            if (FORCE_EXTERNAL_PREFIXES.any {
+                    path.startsWith(it)
+                }) {
+                return false
+            }
+            return INTERNAL_ARTIFACT_PREFIXES.any {
+                path.startsWith(it)
+            }
+        }
+
+        /**
+         * Creates digest for the given contents.
+         *
+         * @param contents file contents
+         * @param fileName original file name
+         * @param algorithm Algorithm to use
+         *
+         * @return a pair if <new file name> : <digest bytes>
+         */
+        @VisibleForTesting
+        internal fun digest(
+            contents: ByteArray,
+            fileName: String,
+            algorithm: String
+        ): Pair<String, ByteArray> {
+            val messageDigest = MessageDigest.getInstance(algorithm)
+            val digestBytes = messageDigest.digest(contents)
+            val builder = StringBuilder()
+            for (byte in digestBytes) {
+                builder.append(String.format("%02x", byte))
+            }
+            val signatureFileName = "$fileName.${algorithm.lowercase(Locale.US)}"
+            val resultBytes = builder.toString().toByteArray(Charsets.UTF_8)
+            return signatureFileName to resultBytes
+        }
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/Log4jExt.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/Log4jExt.kt
new file mode 100644
index 0000000..dfc2c95
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/Log4jExt.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.build.importMaven
+
+import org.apache.logging.log4j.Level
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.core.LoggerContext
+import java.util.concurrent.TimeUnit
+
+internal fun enableInfoLogs() {
+    val ctx = LogManager.getContext(false) as LoggerContext
+    ctx.configuration.rootLogger.level = Level.INFO
+}
+
+internal fun enableVerboseLogs() {
+    val ctx = LogManager.getContext(false) as LoggerContext
+    ctx.configuration.rootLogger.level = Level.TRACE
+}
+
+internal fun flushLogs() {
+    val ctx = LogManager.getContext(false) as LoggerContext
+    ctx.stop(10, TimeUnit.SECONDS)
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/Main.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/Main.kt
new file mode 100644
index 0000000..05e083b
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/Main.kt
@@ -0,0 +1,387 @@
+/*
+ * 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.build.importMaven
+
+import com.github.ajalt.clikt.core.CliktCommand
+import com.github.ajalt.clikt.core.Context
+import com.github.ajalt.clikt.core.UsageError
+import com.github.ajalt.clikt.core.subcommands
+import com.github.ajalt.clikt.parameters.arguments.argument
+import com.github.ajalt.clikt.parameters.arguments.multiple
+import com.github.ajalt.clikt.parameters.options.convert
+import com.github.ajalt.clikt.parameters.options.default
+import com.github.ajalt.clikt.parameters.options.flag
+import com.github.ajalt.clikt.parameters.options.option
+import com.github.ajalt.clikt.parameters.options.required
+import com.github.ajalt.clikt.parameters.types.int
+import okio.FileSystem
+import okio.Path
+import okio.Path.Companion.toPath
+import org.apache.logging.log4j.kotlin.logger
+import kotlin.system.exitProcess
+
+/**
+ * Base class for all commands which only reads the support repo folder.
+ */
+internal abstract class BaseCommand(
+    help: String,
+    treatUnknownOptionsAsArgs: Boolean = false,
+    invokeWithoutSubcommand: Boolean = false,
+) : CliktCommand(
+    help = help,
+    invokeWithoutSubcommand = invokeWithoutSubcommand,
+    treatUnknownOptionsAsArgs = treatUnknownOptionsAsArgs
+) {
+    private var interceptor: ((Context) -> Unit)? = null
+    protected val logger by lazy {
+        // make this lazy so that it can be created after root logger config is changed.
+        logger("main")
+    }
+    internal val supportRepoFolder by option(
+        help = """
+            Path to the support repository (frameworks/support).
+            By default, it is inherited from the build of import maven itself.
+        """.trimIndent(),
+        envvar = "SUPPORT_REPO"
+    )
+
+    internal val verbose by option(
+        names = arrayOf("-v", "--verbose"),
+        help = """
+            Enables verbose logging
+        """.trimIndent()
+    ).flag(
+        default = false
+    )
+
+    /**
+     * Utility method to get the value or infer from the support root folder based on the given
+     * [relativePath].
+     */
+    protected fun String?.orFromSupportRepoFolder(
+        relativePath: String,
+    ): Path {
+        return when {
+            this != null -> this.toPath()
+            supportRepoFolder != null -> supportRepoFolder!!.toPath() / relativePath
+            else -> EnvironmentConfig.supportRoot / relativePath
+        }
+    }
+
+    /**
+     * Disables executing the command, which is useful for testing.
+     */
+    fun intercept(interceptor: (Context) -> Unit) {
+        this.interceptor = interceptor
+        registeredSubcommands().forEach {
+            (it as BaseCommand).intercept(interceptor)
+        }
+    }
+
+    final override fun run() {
+        if (verbose) {
+            enableVerboseLogs()
+        } else {
+            enableInfoLogs()
+        }
+        if (interceptor != null) {
+            interceptor!!.invoke(currentContext)
+        } else {
+            execute()
+        }
+    }
+
+    abstract fun execute()
+}
+
+/**
+ * Base class to import maven artifacts.
+ */
+internal abstract class BaseImportMavenCommand(
+    invokeWithoutSubcommand: Boolean = false,
+    help: String
+) : BaseCommand(
+    help = help,
+    invokeWithoutSubcommand = invokeWithoutSubcommand,
+    treatUnknownOptionsAsArgs = true,
+) {
+    internal val prebuiltsFolder by option(
+        help = """
+            Path to the prebuilts folder. Can be relative to the current working
+            directory.
+            By default, inherited from the support-repo root folder.
+        """.trimIndent()
+    )
+    internal val androidXBuildId by option(
+        names = arrayOf("--androidx-build-id"),
+        help = """
+            The build id of https://ci.android.com/builds/branches/aosp-androidx-main/grid?
+            to use for fetching androidx prebuilts.
+        """.trimIndent()
+    ).int()
+    internal val metalavaBuildId by option(
+        help = """
+            The build id of https://androidx.dev/metalava/builds to fetch metalava from.
+        """.trimIndent()
+    ).int()
+    internal val allowJetbrainsDev by option(
+        help = """
+            Whether or not to allow artifacts to be fetched from Jetbrains' dev repository
+            E.g. https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev
+        """.trimIndent()
+    ).flag()
+
+    internal val redownload by option(
+        help = """
+            If set to true, local repositories will be ignored while resolving artifacts so
+            all of them will be redownloaded.
+        """.trimIndent()
+    ).flag(default = false)
+
+    internal val repositories by option(
+        help = """
+            Comma separated list of additional repositories.
+        """.trimIndent()
+    ).convert("COMMA SEPARATED URLS") {
+        it.split(',')
+    }
+
+    internal val cleanLocalRepo by option(
+        help = """
+            This flag tries to remove unnecessary / bad files from the local maven repository.
+            It must be used with the `redownload` flag.
+            For instance, if we refetch a particular artifact and the download folder has some files
+            that are not re-fetched, they'll be deleted.
+        """.trimIndent()
+    ).flag(default = false)
+
+    internal val explicitlyFetchInheritedDependencies by option(
+        help = """
+            If set, all inherited dependencies will be fetched individually, with their own
+            dependencies.
+            For instance, for the given dependency tree:
+            artifact1:v1
+              artifact2:v2
+                artifact3:v1
+              artifact3:v3
+            When this script is invoked with `artifact1:v1`;
+            If this flag is `false`, we'll only fetch artifact1:v1, artifact2:v2, artifact3:v3.
+            If this flag is `true`, we'll fetch `artifact3:v1` as well (because artifact2:v2
+            declares a dependency on it even though it is overridden by the dependency of
+            artifact1:v1
+        """.trimIndent()
+    ).flag(default = false)
+
+    /**
+     * Return the list of artifacts to fetch.
+     */
+    abstract fun artifacts(): List<String>
+
+    override fun execute() {
+        if (currentContext.invokedSubcommand != null) {
+            // skip, invoking a sub command instead
+            return
+        }
+        val artifactsToBeResolved = artifacts()
+        val extraRepositories = mutableListOf<String>()
+        androidXBuildId?.let {
+            extraRepositories.add(ArtifactResolver.createAndroidXRepo(it))
+        }
+        metalavaBuildId?.let {
+            extraRepositories.add(ArtifactResolver.createMetalavaRepo(it))
+        }
+        if (allowJetbrainsDev) {
+            extraRepositories.addAll(ArtifactResolver.jetbrainsRepositories)
+        }
+        if (cleanLocalRepo) {
+            check(redownload) {
+                """
+                    Passing clean repo without passing redownload might break the local repository
+                    since some files might've been used during resolution.
+                """.trimIndent()
+            }
+        }
+        val downloadFolder = prebuiltsFolder.orFromSupportRepoFolder(
+            "../../prebuilts/androidx"
+        )
+        val downloader = LocalMavenRepoDownloader(
+            fileSystem = FileSystem.SYSTEM,
+            internalFolder = downloadFolder / "internal",
+            externalFolder = downloadFolder / "external"
+        )
+        repositories?.let {
+            extraRepositories.addAll(it)
+        }
+        val resolvedArtifacts = ArtifactResolver.resolveArtifacts(
+            artifacts = artifactsToBeResolved,
+            additionalRepositories = extraRepositories,
+            explicitlyFetchInheritedDependencies = explicitlyFetchInheritedDependencies,
+            localRepositories = if (redownload) {
+                emptyList()
+            } else {
+                listOf(
+                    "file:///" + downloader.internalFolder.toString(),
+                    "file:///" + downloader.externalFolder.toString(),
+                )
+            },
+            downloadObserver = downloader
+        )
+        if (cleanLocalRepo) {
+            downloader.cleanupLocalRepositories()
+        }
+
+        val downloadedFiles = downloader.getDownloadedFiles()
+        logger.info {
+            """
+                Import artifact action completed.
+                Resolved ${resolvedArtifacts.size} artifacts.
+                Downloaded ${downloadedFiles.size} files.
+            """.trimIndent()
+        }
+        if (downloadedFiles.isEmpty()) {
+            logger.warn(
+                """
+                Didn't download any files. It might be either a bug or all files might be available
+                in the local prebuilts.
+
+                If you think it is a bug, please re-run the command with `--verbose` and file
+                a bug with the output.
+                https://issuetracker.google.com/issues/new?component=705292
+                """.trimIndent()
+            )
+        }
+        flushLogs()
+    }
+}
+
+/**
+ * Imports the maven artifacts in the [artifacts] parameter.
+ */
+internal class ImportArtifact : BaseImportMavenCommand(
+    help = "Imports given artifacts",
+    invokeWithoutSubcommand = true
+) {
+    private val args by argument(
+        help = """
+            The dependency notation of the artifact you want to add to the prebuilts folder.
+            Can be passed multiple times.
+            E.g. android.arch.work:work-runtime-ktx:1.0.0-alpha07
+        """.trimIndent()
+    ).multiple(
+        required = false,
+        default = emptyList()
+    )
+    private val artifacts by option(
+        help = """
+            The dependency notation of the artifact you want to add to the prebuilts folder.
+            E.g. android.arch.work:work-runtime-ktx:1.0.0-alpha07
+            Multiple artifacts can be provided with a `,` in between them.
+        """.trimIndent()
+    ).default("")
+
+    override fun artifacts(): List<String> {
+        // artifacts passed via --artifacts
+        val optionArtifacts = artifacts.split(',')
+        // artficats passed as command line argument
+        val argArtifacts = args.flatMap { it.split(',') }
+        val artifactsToBeResolved = (optionArtifacts + argArtifacts).distinct()
+            .filter {
+                it.isNotBlank()
+            }
+        if (artifactsToBeResolved.isEmpty()) {
+            // since we run this command as the default one, we cannot enforce arguments.
+            // instead, we check them in first access
+            throw UsageError(
+                text = """
+                        Missing artifact coordinates.
+                        You can either pass them as arguments or explicitly via --artifacts option.
+                        e.g. ./importMaven.sh foo:bar:baz:123
+                             ./importMaven.sh --artifacts foo:bar:baz:123
+                        help:
+                        ${getFormattedHelp()}
+                    """.trimIndent()
+            )
+        }
+        return artifactsToBeResolved
+    }
+}
+
+/**
+ * Downloads konan binaries that are needed to compile native targets.
+ */
+internal class ImportKonanBinariesCommand : BaseCommand(
+    help = "Downloads konan binaries"
+) {
+    internal val konanPrebuiltsFolder by option(
+        help = """
+            Path to the prebuilts folder. Can be relative to the current working
+            directory.
+            By default, inherited from the support-repo root folder.
+        """.trimIndent()
+    )
+    internal val konanCompilerVersion by option(
+        help = """
+            Konan compiler version to download. This is usually your kotlin version.
+        """.trimIndent()
+    ).required()
+
+    override fun execute() {
+        val downloadFolder = konanPrebuiltsFolder.orFromSupportRepoFolder(
+            "../../prebuilts/androidx/konan"
+        )
+        KonanPrebuiltsDownloader(
+            fileSystem = FileSystem.SYSTEM,
+            downloadPath = downloadFolder,
+            testMode = false
+        ).download(
+            konanCompilerVersion
+        )
+    }
+}
+
+/**
+ * Imports all libraries declared in a toml file.
+ */
+internal class ImportToml : BaseImportMavenCommand(
+    help = "Downloads all artifacts declared in the project's toml file"
+) {
+    internal val tomlFile by option(
+        help = """
+            Path to the toml file. If not provided, main androidx toml file is obtained from the
+            supportRepoFolder argument.
+        """.trimIndent()
+    )
+
+    override fun artifacts(): List<String> {
+        val file = tomlFile.orFromSupportRepoFolder(
+            "gradle/libs.versions.toml"
+        )
+        return ImportVersionCatalog.load(
+            fileSystem = FileSystem.SYSTEM,
+            file = file
+        )
+    }
+}
+
+internal fun createCliCommands() = ImportArtifact()
+    .subcommands(
+        ImportKonanBinariesCommand(), ImportToml()
+    )
+
+fun main(args: Array<String>) {
+    createCliCommands().main(args)
+    exitProcess(0)
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/MavenRepositoryProxy.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/MavenRepositoryProxy.kt
new file mode 100644
index 0000000..a7d13e5
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/MavenRepositoryProxy.kt
@@ -0,0 +1,193 @@
+/*
+ * 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.build.importMaven
+
+import io.ktor.client.HttpClient
+import io.ktor.client.engine.okhttp.OkHttp
+import io.ktor.client.request.header
+import io.ktor.client.request.request
+import io.ktor.client.statement.HttpResponse
+import io.ktor.client.statement.bodyAsChannel
+import io.ktor.http.Headers
+import io.ktor.http.HttpMethod
+import io.ktor.http.contentType
+import io.ktor.http.isSuccess
+import io.ktor.server.application.call
+import io.ktor.server.engine.embeddedServer
+import io.ktor.server.netty.Netty
+import io.ktor.server.request.path
+import io.ktor.server.response.respondBytes
+import io.ktor.server.routing.get
+import io.ktor.server.routing.routing
+import io.ktor.util.toByteArray
+import kotlinx.coroutines.runBlocking
+import org.apache.logging.log4j.kotlin.logger
+import java.net.URI
+import java.net.URL
+
+/**
+ * Creates a local proxy server for given the artifactory url.
+ *
+ * @see MavenRepositoryProxy.Companion.startAll
+ */
+class MavenRepositoryProxy private constructor(
+    delegateHost: String,
+    val downloadObserver: DownloadObserver?
+) {
+    init {
+        check(delegateHost.startsWith("http")) {
+            "Unsupported url: $delegateHost. Only http(s) urls are supported"
+        }
+    }
+
+    private val logger = logger("MavenProxy[$delegateHost]")
+
+    private val delegateHost = delegateHost.trimEnd {
+        it == '/'
+    }
+
+    fun <T> start(block: (URI) -> T): T {
+        val client = HttpClient(OkHttp)
+        val server = embeddedServer(Netty, port = 0 /*random port*/) {
+            routing {
+                get("/{...}") {
+                    val path = this.call.request.path()
+                    val incomingHeaders = this.call.request.headers
+                    logger.trace {
+                        "Request($path)"
+                    }
+
+                    try {
+                        val (clientResponse, responseBytes) = requestFromDelegate(
+                            path,
+                            client,
+                            incomingHeaders
+                        )
+                        call.respondBytes(
+                            bytes = responseBytes,
+                            contentType = clientResponse.contentType(),
+                            status = clientResponse.status
+                        ).also {
+                            logger.trace {
+                                "Success ($path)"
+                            }
+                        }
+                    } catch (ex: Throwable) {
+                        logger.error(ex) {
+                            "Failed ($path): ${ex.message}"
+                        }
+                        throw ex
+                    }
+                }
+            }
+        }
+        return try {
+            server.start(wait = false)
+            val url = runBlocking {
+                server.resolvedConnectors().first().let {
+                    URL(
+                        it.type.name.lowercase(),
+                        it.host,
+                        it.port,
+                        ""
+                    )
+                    URI("${it.type.name.lowercase()}://${it.host}:${it.port}")
+                }
+            }
+            block(url)
+        } finally {
+            runCatching {
+                client.close()
+            }
+            runCatching {
+                server.stop()
+            }
+        }
+    }
+
+    private suspend fun requestFromDelegate(
+        path: String,
+        client: HttpClient,
+        incomingHeaders: Headers
+    ): Pair<HttpResponse, ByteArray> {
+        val delegatedUrl = "$delegateHost$path"
+        val clientResponse = client.request(delegatedUrl) {
+            incomingHeaders.forEach { key, value ->
+                // don't copy host header since we are proxying from localhost.
+                if (key != "Host") {
+                    header(key, value)
+                }
+            }
+            method = HttpMethod.Get
+        }
+        val responseBytes = clientResponse.bodyAsChannel().toByteArray()
+        if (clientResponse.status.isSuccess()) {
+            downloadObserver?.onDownload(
+                path = path.dropWhile { it == '/' },
+                bytes = responseBytes
+            )
+        }
+        return Pair(clientResponse, responseBytes)
+    }
+
+    companion object {
+        /**
+         * Creates proxy servers for all given artifactory urls.
+         *
+         * It will call the given [block] with local servers that can be provided to gradle as maven
+         * repositories.
+         */
+        fun <T> startAll(
+            repositoryUrls: List<String>,
+            downloadObserver: DownloadObserver?,
+            block: (List<URI>) -> T
+        ): T {
+            val proxies = repositoryUrls.map { url ->
+                MavenRepositoryProxy(
+                    delegateHost = url,
+                    downloadObserver = downloadObserver
+                )
+            }
+            return startAll(
+                proxies = proxies,
+                previousUris = emptyList(),
+                block = block
+            )
+        }
+
+        /**
+         * Recursively start all proxy servers
+         */
+        private fun <T> startAll(
+            proxies: List<MavenRepositoryProxy>,
+            previousUris: List<URI>,
+            block: (List<URI>) -> T
+        ): T {
+            if (proxies.isEmpty()) {
+                return block(previousUris)
+            }
+            val first = proxies.first()
+            return first.start { myUri ->
+                startAll(
+                    proxies = proxies.drop(1),
+                    previousUris = previousUris + myUri,
+                    block = block
+                )
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/ProjectService.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ProjectService.kt
new file mode 100644
index 0000000..dd85164
--- /dev/null
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ProjectService.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.build.importMaven
+
+import org.apache.logging.log4j.kotlin.logger
+import org.gradle.api.Project
+import org.gradle.testfixtures.ProjectBuilder
+import java.io.File
+import java.util.UUID
+
+/**
+ * Helper class to create Gradle projects
+ */
+object ProjectService {
+    private val logger = logger("ProjectService")
+    private val tmpFolder = System.getProperty("java.io.tmpdir").let { File(it) }
+
+    fun createProject(): Project {
+        val folder = randomProjectFolder()
+        logger.trace {
+            "created project at $folder"
+        }
+        return ProjectBuilder.builder().withProjectDir(
+            folder.resolve("project").also {
+                it.mkdirs()
+            }
+        ).withGradleUserHomeDir(
+            folder.resolve("gradle-home").also {
+                it.mkdirs()
+            }
+        ).withName("importMaven")
+            .build()
+    }
+
+    private fun randomProjectFolder(): File {
+        while (true) {
+            val file = tmpFolder.resolve(randomId())
+            if (!file.exists()) {
+                file.mkdirs()
+                file.deleteOnExit()
+                return file
+            }
+        }
+    }
+
+    private fun randomId(): String = UUID.randomUUID().toString().subSequence(0, 6).toString()
+}
\ No newline at end of file
diff --git a/development/importMaven/src/test/kotlin/androidx/build/importMaven/ArtifactResolverTest.kt b/development/importMaven/src/test/kotlin/androidx/build/importMaven/ArtifactResolverTest.kt
new file mode 100644
index 0000000..0036d64
--- /dev/null
+++ b/development/importMaven/src/test/kotlin/androidx/build/importMaven/ArtifactResolverTest.kt
@@ -0,0 +1,462 @@
+/*
+ * 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.build.importMaven
+
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import okio.FileSystem
+import okio.Path
+import okio.Path.Companion.toPath
+import okio.buffer
+import okio.fakefilesystem.FakeFileSystem
+import org.junit.Test
+
+/**
+ * Integration tests for [ArtifactResolver]
+ */
+class ArtifactResolverTest {
+    private val fakeFileSystem = FakeFileSystem().also {
+        it.emulateUnix()
+    }
+    private val downloader = LocalMavenRepoDownloader(
+        fileSystem = fakeFileSystem,
+        internalFolder = fakeFileSystem.workingDirectory / "internal",
+        externalFolder = fakeFileSystem.workingDirectory / "external"
+    )
+
+    @Test
+    fun downloadAndroidXPrebuilt() {
+        ArtifactResolver.resolveArtifacts(
+            artifacts = listOf("androidx.room:room-runtime:2.5.0-SNAPSHOT"),
+            additionalRepositories = listOf(
+                ArtifactResolver.createAndroidXRepo(8657806)
+            ),
+            downloadObserver = downloader
+        )
+        assertThat(
+            fakeFileSystem.allPathStrings()
+        ).containsAtLeast(
+            "/internal/androidx/room/room-runtime/2.5.0-SNAPSHOT/maven-metadata.xml",
+            "/internal/androidx/room/room-common/2.5.0-SNAPSHOT/maven-metadata.xml",
+        )
+        // the downloaded file for snapshot will have a version.
+        // If we assert exact name, it will fail when build is no longer available. Instead, we look
+        // into files.
+        val roomRuntimeFiles = fakeFileSystem.list(
+            "/internal/androidx/room/room-runtime/2.5.0-SNAPSHOT/".toPath()
+        )
+        assertWithMessage(
+            roomRuntimeFiles.joinToString("\n") { it.toString() }
+        ).that(
+            roomRuntimeFiles.any {
+                it.name.startsWith("room-runtime-") &&
+                        it.name.endsWith("aar")
+            }).isTrue()
+    }
+
+    @Test
+    fun testAndroidArtifactsWithMetadata() {
+        ArtifactResolver.resolveArtifacts(
+            listOf("androidx.room:room-runtime:2.4.2"),
+            downloadObserver = downloader
+        )
+        assertThat(fakeFileSystem.allPathStrings()).containsAtLeastElementsIn(
+            "/internal/androidx/room/room-runtime/2.4.2/".toPath().expectedAar(
+                signed = false,
+                "room-runtime-2.4.2"
+            ) + "/internal/androidx/room/room-common/2.4.2/".toPath().expectedJar(
+                signed = false,
+                "room-common-2.4.2"
+            ) + "/internal/androidx/sqlite/sqlite-framework/2.2.0".toPath().expectedAar(
+                signed = false,
+                "sqlite-framework-2.2.0"
+            ) + "/internal/androidx/annotation/annotation/1.1.0".toPath().expectedFiles(
+                signed = false,
+                // this annotations artifact is old, it doesn't have module metadata
+                "annotation-1.1.0.jar", "annotation-1.1.0.pom"
+            )
+        )
+        // don't copy licenses for internal artifacts
+        assertThat(fakeFileSystem.allPathStrings()).doesNotContain(
+            "/internal/androidx/room/room-runtime/2.4.2/LICENSE"
+        )
+    }
+
+    @Test
+    fun testGmavenJar() {
+        ArtifactResolver.resolveArtifacts(
+            listOf("androidx.room:room-common:2.4.2"),
+            downloadObserver = downloader
+        )
+        assertThat(fakeFileSystem.allPathStrings()).containsAtLeastElementsIn(
+            "/internal/androidx/room/room-common/2.4.2/".toPath().expectedJar(
+                signed = false,
+                "room-common-2.4.2"
+            ) + "/internal/androidx/annotation/annotation/1.1.0".toPath().expectedFiles(
+                signed = false,
+                // this annotations artifact is old, it doesn't have module metadata
+                "annotation-1.1.0.jar", "annotation-1.1.0.pom"
+            )
+        )
+        // don't copy licenses for internal artifacts
+        assertThat(fakeFileSystem.allPathStrings()).doesNotContain(
+            "/internal/androidx/room/room-runtime/2.4.2/LICENSE"
+        )
+    }
+
+    @Test
+    fun ensureInternalPomsAreReWritten() {
+        val bytes = this::class.java
+            .getResourceAsStream("/pom-with-aar-deps.pom")!!.readBytes()
+        downloader.onDownload("notAndroidx/subject.pom", bytes)
+        val externalContents = fakeFileSystem.read(
+            "external/notAndroidx/subject.pom".toPath()
+        ) {
+            this.readUtf8()
+        }.lines().map { it.trim() }
+        assertThat(externalContents).contains("<type>aar</type>")
+        assertThat(externalContents).doesNotContain("<!--<type>aar</type>-->")
+
+        downloader.onDownload("androidx/subject.pom", bytes)
+        val internalContents = fakeFileSystem.read(
+            "internal/androidx/subject.pom".toPath()
+        ) {
+            this.readUtf8()
+        }.lines().map { it.trim() }
+        assertThat(internalContents).doesNotContain("<type>aar</type>")
+        assertThat(internalContents).contains("<!--<type>aar</type>-->")
+
+        // assert that original sha/md5 is preserved when file is re-written.
+        val sha1 = LocalMavenRepoDownloader.digest(
+            contents = bytes,
+            fileName = "_",
+            algorithm = "SHA1"
+        ).second.toString(Charsets.UTF_8)
+        val md5 = LocalMavenRepoDownloader.digest(
+            contents = bytes,
+            fileName = "_",
+            algorithm = "MD5"
+        ).second.toString(Charsets.UTF_8)
+        assertThat(
+            fakeFileSystem.readText("external/notAndroidx/subject.pom.md5")
+        ).isEqualTo(md5)
+        assertThat(
+            fakeFileSystem.readText("internal/androidx/subject.pom.md5")
+        ).isEqualTo(md5)
+        assertThat(
+            fakeFileSystem.readText("external/notAndroidx/subject.pom.sha1")
+        ).isEqualTo(sha1)
+        assertThat(
+            fakeFileSystem.readText("internal/androidx/subject.pom.sha1")
+        ).isEqualTo(sha1)
+    }
+
+    @Test
+    fun testKotlinArtifactsWithKmp_fetchInherited() = testKotlinArtifactsWithKmp(true)
+
+    @Test
+    fun testKotlinArtifactsWithKmp() = testKotlinArtifactsWithKmp(false)
+
+    private fun testKotlinArtifactsWithKmp(explicitlyFetchInherited: Boolean) {
+        ArtifactResolver.resolveArtifacts(
+            listOf("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1"),
+            downloadObserver = downloader,
+            explicitlyFetchInheritedDependencies = explicitlyFetchInherited
+        )
+        val expectedKlibs = listOf(
+            "atomicfu-linuxx64/0.17.0/atomicfu-linuxx64-0.17.0.klib",
+            "atomicfu-macosarm64/0.17.0/atomicfu-macosarm64-0.17.0.klib",
+            "atomicfu-macosx64/0.17.0/atomicfu-macosx64-0.17.0.klib"
+        ).map {
+            "/external/org/jetbrains/kotlinx/$it"
+        }
+        assertThat(fakeFileSystem.allPathStrings()).containsAtLeastElementsIn(
+            "/external/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.6.1".toPath()
+                .expectedFiles(
+                    signed = true,
+                    "kotlinx-coroutines-core-1.6.1-all.jar",
+                    "kotlinx-coroutines-core-1.6.1-sources.jar",
+                    "kotlinx-coroutines-core-1.6.1.module",
+                ) + "/external/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.0".toPath()
+                .expectedFiles(
+                    signed = true,
+                    "kotlin-stdlib-common-1.6.0.jar",
+                    "kotlin-stdlib-common-1.6.0.pom",
+                ) + expectedKlibs +
+                    "/external/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.0/LICENSE"
+        )
+        // atomic-fu jvm is not a dependency
+        val atomicFuJvmFiles =
+            "/external/org/jetbrains/kotlinx/atomicfu-jvm/0.17.0".toPath().expectedJar(
+                signed = true,
+                "atomicfu-jvm-0.17.0"
+            )
+        if (explicitlyFetchInherited) {
+            assertThat(fakeFileSystem.allPathStrings()).containsAtLeastElementsIn(
+                atomicFuJvmFiles
+            )
+        } else {
+            assertThat(fakeFileSystem.allPathStrings()).doesNotContain(
+                atomicFuJvmFiles
+            )
+        }
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun invalidArtifact() {
+        ArtifactResolver.resolveArtifacts(
+            listOf("this.artifact.doesnot:exists:1.0.0"),
+            downloadObserver = downloader
+        )
+    }
+
+    @Test
+    fun testDownloadAtomicFu() {
+        ArtifactResolver.resolveArtifacts(
+            listOf("org.jetbrains.kotlinx:atomicfu:0.17.0"),
+            downloadObserver = downloader
+        )
+        val expectedKlibs = listOf(
+            "atomicfu-linuxx64/0.17.0/atomicfu-linuxx64-0.17.0.klib",
+            "atomicfu-macosarm64/0.17.0/atomicfu-macosarm64-0.17.0.klib",
+            "atomicfu-macosx64/0.17.0/atomicfu-macosx64-0.17.0.klib"
+        ).map {
+            "/external/org/jetbrains/kotlinx/$it"
+        }
+        assertThat(fakeFileSystem.allPathStrings()).containsAtLeastElementsIn(
+            "/external/org/jetbrains/kotlinx/atomicfu-jvm/0.17.0".toPath()
+                .expectedJar(
+                    signed = true,
+                    "atomicfu-jvm-0.17.0"
+                ) + expectedKlibs +
+                    "/external/org/jetbrains/kotlin/kotlin-stdlib-common/1.6.0/LICENSE"
+        )
+    }
+
+    @Test
+    fun testSignatureFiles() {
+        ArtifactResolver.resolveArtifacts(
+            listOf("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.1"),
+            downloadObserver = downloader
+        )
+        assertThat(fakeFileSystem.allPathStrings()).containsAtLeastElementsIn(
+            "/external/org/jetbrains/kotlinx/kotlinx-coroutines-test-linuxx64/1.6.1/".toPath()
+                .expectedFiles(
+                    signed = true,
+                    "kotlinx-coroutines-test-linuxx64-1.6.1.klib",
+                    "kotlinx-coroutines-test-linuxx64-1.6.1.module",
+                )
+        )
+    }
+
+    @Test
+    fun testSignedArtifactWithoutKeyServerEntry() {
+        // https://repo1.maven.org/maven2/org/assertj/assertj-core/3.11.1/
+        // these artifacts are signed but their signature is not on any public key-server
+        // we cannot trust them so instead these builds should rely on shas
+        ArtifactResolver.resolveArtifacts(
+            listOf("org.assertj:assertj-core:3.11.1"),
+            downloadObserver = downloader
+        )
+        assertThat(fakeFileSystem.allPathStrings()).containsAtLeastElementsIn(
+            "/external/org/assertj/assertj-core/3.11.1/".toPath().expectedFiles(
+                signed = true,
+                "assertj-core-3.11.1-sources.jar",
+                "assertj-core-3.11.1.jar",
+                "assertj-core-3.11.1.pom",
+            )
+        )
+    }
+
+    @Test
+    fun noArtifactsAreFetchedWhenInternalRepoIsProvided() {
+        val localRepoUris = EnvironmentConfig.supportRoot.let {
+            listOf(
+                "file:///$it/../../prebuilts/androidx/external",
+                "file:///$it/../../prebuilts/androidx/internal",
+            )
+        }
+        ArtifactResolver.resolveArtifacts(
+            listOf("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1"),
+            downloadObserver = downloader,
+            localRepositories = localRepoUris
+        )
+        assertThat(fakeFileSystem.allPaths).isEmpty()
+    }
+
+    @Test
+    fun testMetalavaDownload() {
+        ArtifactResolver.resolveArtifacts(
+            artifacts = listOf(
+                "com.android.tools.metalava:metalava:1.0.0-alpha06"
+            ),
+            additionalRepositories = listOf(
+                ArtifactResolver.createMetalavaRepo(8634556)
+            ),
+            downloadObserver = downloader
+        )
+
+        assertThat(fakeFileSystem.allPathStrings()).containsAtLeastElementsIn(
+            "/external/com/android/tools/metalava/metalava/1.0.0-alpha06/".toPath().expectedJar(
+                signed = false,
+                "metalava-1.0.0-alpha06"
+            ).filterNot {
+                // metalava doesn't ship sources.
+                it.contains("sources")
+            }
+        )
+    }
+
+    @Test
+    fun oldArtifactWithoutMetadata() {
+        ArtifactResolver.resolveArtifacts(
+            artifacts = listOf(
+                "androidx.databinding:viewbinding:4.1.2"
+            ),
+            downloadObserver = downloader
+        )
+        assertThat(fakeFileSystem.allPathStrings()).containsAtLeastElementsIn(
+            "/external/androidx/databinding/viewbinding/4.1.2".toPath().expectedAar(
+                signed = false,
+                "viewbinding-4.1.2"
+            ).filterNot {
+                // only pom in this artifact
+                it.contains("module")
+            }
+        )
+    }
+
+    @Test
+    fun testRunner() {
+        ArtifactResolver.resolveArtifacts(
+            artifacts = listOf(
+                "androidx.test:runner:1.4.0"
+            ),
+            downloadObserver = downloader
+        )
+        assertThat(fakeFileSystem.allPathStrings()).containsAtLeastElementsIn(
+            "/internal/androidx/test/runner/1.4.0/".toPath().expectedAar(
+                signed = false,
+                "runner-1.4.0"
+            ).filterNot {
+                // old artifact without metadata
+                it.contains("module")
+            }
+        )
+    }
+
+    /**
+     * Assert that if same artifact is referenced by two libraries but one of them uses a newer
+     * version, we fetch both versions.
+     */
+    @Test
+    fun isolateConfigurations() {
+        ArtifactResolver.resolveArtifacts(
+            listOf(
+                "androidx.room:room-runtime:2.4.2",
+                "androidx.room:room-runtime:2.4.0",
+            ),
+            downloadObserver = downloader
+        )
+        assertThat(fakeFileSystem.allPathStrings()).containsAtLeastElementsIn(
+            "/internal/androidx/room/room-common/2.4.2/".toPath().expectedJar(
+                signed = false,
+                "room-common-2.4.2"
+            ) +
+                    "/internal/androidx/room/room-common/2.4.0/".toPath().expectedJar(
+                        signed = false,
+                        "room-common-2.4.0"
+                    )
+        )
+    }
+
+    @Test
+    fun downloadWithGradlePluginSpecs() {
+        ArtifactResolver.resolveArtifacts(
+            listOf("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.0"),
+            downloadObserver = downloader
+        )
+        assertThat(fakeFileSystem.allPathStrings()).containsAtLeast(
+            "/external/org/jetbrains/kotlin/kotlin-gradle-plugin/1.7.0/" +
+                    "kotlin-gradle-plugin-1.7.0-gradle70.jar",
+            "/external/org/jetbrains/kotlin/kotlin-gradle-plugin/1.7.0/" +
+                    "kotlin-gradle-plugin-1.7.0.jar"
+        )
+    }
+
+    private fun FakeFileSystem.allPathStrings() = allPaths.map {
+        it.toString()
+    }
+
+    private fun FileSystem.readText(path: String) =
+        this.openReadOnly(path.toPath()).source().buffer().use {
+            it.readUtf8()
+        }
+
+    /**
+     * Utility method to easily create files in a given folder path
+     */
+    private fun Path.expectedFiles(
+        signed: Boolean,
+        vararg fileNames: String,
+    ): List<String> {
+        val originals = if (signed) {
+            fileNames.flatMap {
+                listOf(it, "$it.asc")
+            }
+        } else {
+            fileNames.toList()
+        }
+
+        return originals.map { "$this/$it" }.flatMap {
+            listOf(it, "$it.md5", "$it.sha1")
+        }
+    }
+
+    private fun Path.expectedAar(
+        signed: Boolean,
+        prefix: String,
+    ) = expectedFiles(
+        signed = signed,
+        *COMMON_FILES_FOR_AARS.map {
+            "$prefix$it"
+        }.toTypedArray()
+    ) + expectedFiles(
+        // gradle doesn't need the signature for pom when there is a module file.
+        signed = false,
+        "$prefix.pom"
+    )
+
+    private fun Path.expectedJar(
+        signed: Boolean,
+        prefix: String,
+    ) = expectedFiles(
+        signed = signed,
+        *COMMON_FILES_FOR_JARS.map {
+            "$prefix$it"
+        }.toTypedArray()
+    ) + expectedFiles(
+        // gradle doesn't need the signature for pom when there is a module file.
+        signed = false,
+        "$prefix.pom"
+    )
+
+    companion object {
+        val COMMON_FILES_FOR_AARS = listOf(".aar", "-sources.jar", ".module")
+        val COMMON_FILES_FOR_JARS = listOf(".jar", "-sources.jar", ".module")
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/test/kotlin/androidx/build/importMaven/CliCommandParserTest.kt b/development/importMaven/src/test/kotlin/androidx/build/importMaven/CliCommandParserTest.kt
new file mode 100644
index 0000000..dfcc22a
--- /dev/null
+++ b/development/importMaven/src/test/kotlin/androidx/build/importMaven/CliCommandParserTest.kt
@@ -0,0 +1,198 @@
+/*
+ * 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.build.importMaven
+
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Test
+
+class CliCommandParserTest {
+    @Test
+    fun artifactCoordinatesViaArguments() {
+        runCommand<ImportArtifact>("foo:bar:123") { cmd ->
+            assertThat(
+                cmd.artifacts()
+            ).containsExactly("foo:bar:123")
+        }
+    }
+
+    @Test
+    fun multipleArtifactCoordinatesViaArguments() {
+        runCommand<ImportArtifact>("foo:123", "bar:2.3.4") { cmd ->
+            assertThat(
+                cmd.artifacts()
+            ).containsExactly("foo:123", "bar:2.3.4")
+        }
+    }
+
+    @Test
+    fun mixedArtifactAndArgumentInputs() {
+        runCommand<ImportArtifact>("--artifacts", "foo:123,foo:345", "bar:2.3.4") { cmd ->
+            assertThat(
+                cmd.artifacts()
+            ).containsExactly("foo:123", "foo:345", "bar:2.3.4")
+        }
+    }
+
+    @Test
+    fun artifactCoordinatesAsCommaSeparatedArguments() {
+        runCommand<ImportArtifact>("foo:bar,bar:baz") { cmd ->
+            assertThat(
+                cmd.artifacts()
+            ).containsExactly(
+                "foo:bar", "bar:baz"
+            )
+        }
+    }
+
+    @Test
+    fun importArtifactParameters() {
+        val allSupportedImportMavenBaseArguments = listOf(
+            "--verbose",
+            "--androidx-build-id", "123",
+            "--metalava-build-id", "345",
+            "--support-repo-folder", "support/repo/path",
+            "--allow-jetbrains-dev",
+            "--redownload",
+            "--repositories", "http://a.com,http://b.com",
+            "--clean-local-repo",
+            "--explicitly-fetch-inherited-dependencies"
+        )
+        val validateCommonArguments = { cmd: BaseImportMavenCommand ->
+            assertThat(
+                cmd.androidXBuildId
+            ).isEqualTo(123)
+            assertThat(
+                cmd.verbose
+            ).isTrue()
+            assertThat(
+                cmd.redownload
+            ).isTrue()
+            assertThat(
+                cmd.metalavaBuildId
+            ).isEqualTo(345)
+            assertThat(
+                cmd.supportRepoFolder
+            ).isEqualTo("support/repo/path")
+            assertThat(
+                cmd.allowJetbrainsDev
+            ).isTrue()
+            assertThat(
+                cmd.repositories
+            ).containsExactly(
+                "http://a.com", "http://b.com"
+            )
+            assertThat(
+                cmd.cleanLocalRepo
+            ).isTrue()
+            assertThat(
+                cmd.explicitlyFetchInheritedDependencies
+            ).isTrue()
+        }
+        val importArtifactArgs = allSupportedImportMavenBaseArguments + listOf(
+            "foo:bar",
+            "foo2:bar2",
+            "--artifacts",
+            "bar:baz,bar2:baz2"
+        )
+        runCommand<BaseImportMavenCommand>(
+            *importArtifactArgs.toTypedArray()
+        ) { cmd ->
+            assertThat(
+                cmd.artifacts()
+            ).containsExactly(
+                "foo:bar", "foo2:bar2", "bar:baz", "bar2:baz2"
+            )
+            validateCommonArguments(cmd)
+        }
+        val importTomlArgs = listOf("import-toml") + allSupportedImportMavenBaseArguments
+        runCommand<ImportToml>(
+            *importTomlArgs.toTypedArray()
+        ) { cmd ->
+            validateCommonArguments(cmd)
+        }
+    }
+
+    @Test
+    fun noArguments() {
+        val result = kotlin.runCatching {
+            runCommand<ImportArtifact>() { cmd ->
+                cmd.artifacts()
+            }
+        }
+        assertThat(
+            result.exceptionOrNull()
+        ).hasMessageThat().contains(
+            "Missing artifact coordinates"
+        )
+    }
+
+    @Test
+    fun importToml() {
+        runCommand<ImportToml>("import-toml") { cmd ->
+            assertThat(cmd.tomlFile).isNull()
+        }
+    }
+
+    @Test
+    fun importKonanArtifacts_missingKotlinVersion() {
+        val exception = runInvalidCommand<ImportKonanBinariesCommand>("import-konan-binaries")
+        assertThat(exception).hasMessageThat().contains(
+            "Missing option \"--konan-compiler-version\""
+        )
+    }
+
+    private inline fun <reified T : BaseCommand> runInvalidCommand(
+        vararg args: String
+    ): Throwable {
+        val result = kotlin.runCatching {
+            runCommand<T>(*args) { _ -> }
+        }
+        val exception = result.exceptionOrNull()
+        assertWithMessage("expected the commmand to fail")
+            .that(exception)
+            .isNotNull()
+        return exception!!
+    }
+
+    private inline fun <reified T : BaseCommand> runCommand(
+        vararg args: String,
+        crossinline block: (T) -> Unit
+    ) = createCliCommands().also {
+        var intercepted = false
+        it.intercept { context ->
+            if (context.invokedSubcommand == null) {
+                val cmd = context.command
+                if (T::class.isInstance(cmd)) {
+                    block(cmd as T)
+                } else {
+                    throw AssertionError(
+                        """
+                    Expected to invoke command type of ${T::class} but invoked ${cmd::class}
+                """.trimIndent()
+                    )
+                }
+                intercepted = true
+            }
+        }
+        it.parse(argv = args.toList(), parentContext = null)
+        assertWithMessage(
+            "Expected to intercept execution"
+        ).that(
+            intercepted
+        ).isTrue()
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/test/kotlin/androidx/build/importMaven/GithubLicenseApiTest.kt b/development/importMaven/src/test/kotlin/androidx/build/importMaven/GithubLicenseApiTest.kt
new file mode 100644
index 0000000..1a672da
--- /dev/null
+++ b/development/importMaven/src/test/kotlin/androidx/build/importMaven/GithubLicenseApiTest.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.build.importMaven
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class GithubLicenseApiTest {
+    @Test
+    fun invalidRepoAndOwner() {
+        val response = GithubLicenseApiClient().getProjectLicense(
+            "https://github.com/this-repository-surely-does-not-exist/i-bet-really"
+        )
+        assertThat(response).isNull()
+    }
+
+    @Test
+    fun fetchLicense() {
+        val response = GithubLicenseApiClient().getProjectLicense(
+            "https://github.com/androidX/androidx"
+        )
+        val androidXLicense = this::class.java.getResource(
+            "/androidx-license.txt"
+        )?.openStream()?.use {
+            it.readAllBytes()
+        }?.toString(Charsets.UTF_8)!!
+        assertThat(response?.trim()).isEqualTo(androidXLicense.trim())
+    }
+
+    @Test
+    fun parseRepo() {
+        with(GithubLicenseApiClient()) {
+            assertThat(
+                "https://github.com/hamcrest/JavaHamcrest".extractGithubOwnerAndRepo()
+            ).isEqualTo("hamcrest" to "JavaHamcrest")
+            assertThat(
+                "https://www.github.com/hamcrest/JavaHamcrest".extractGithubOwnerAndRepo()
+            ).isEqualTo("hamcrest" to "JavaHamcrest")
+            assertThat(
+                "not url".extractGithubOwnerAndRepo()
+            ).isNull()
+            assertThat(
+                "https://www.notgithub.com/foo/bar".extractGithubOwnerAndRepo()
+            ).isNull()
+            assertThat(
+                "https://www.github.com/foo/bar/baz".extractGithubOwnerAndRepo()
+            ).isNull()
+            assertThat(
+                "https://www.github.com/foo/bar/".extractGithubOwnerAndRepo()
+            ).isEqualTo("foo" to "bar")
+        }
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/test/kotlin/androidx/build/importMaven/ImportVersionCatalogTest.kt b/development/importMaven/src/test/kotlin/androidx/build/importMaven/ImportVersionCatalogTest.kt
new file mode 100644
index 0000000..b80401b
--- /dev/null
+++ b/development/importMaven/src/test/kotlin/androidx/build/importMaven/ImportVersionCatalogTest.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.build.importMaven
+
+import com.google.common.truth.Truth.assertThat
+import okio.FileSystem
+import org.junit.Test
+
+class ImportVersionCatalogTest {
+    init {
+        enableInfoLogs()
+    }
+
+    @Test
+    fun load() {
+        val path = EnvironmentConfig.supportRoot.resolve("gradle/libs.versions.toml")
+        val versions = ImportVersionCatalog.load(
+            FileSystem.SYSTEM,
+            path
+        )
+        assertThat(
+            versions.size
+        ).isAtLeast(20)
+        assertThat(
+            versions.any {
+                it.contains("kotlin-gradle-plugin")
+            }
+        ).isTrue()
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/test/kotlin/androidx/build/importMaven/KonanPrebuiltsDownloaderTest.kt b/development/importMaven/src/test/kotlin/androidx/build/importMaven/KonanPrebuiltsDownloaderTest.kt
new file mode 100644
index 0000000..059a233
--- /dev/null
+++ b/development/importMaven/src/test/kotlin/androidx/build/importMaven/KonanPrebuiltsDownloaderTest.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.build.importMaven
+
+import com.google.common.truth.Truth.assertThat
+import okio.Path.Companion.toPath
+import okio.fakefilesystem.FakeFileSystem
+import org.junit.Test
+
+class KonanPrebuiltsDownloaderTest {
+    @Test
+    fun download() {
+        val fakeFileSystem = FakeFileSystem().apply {
+            emulateUnix()
+        }
+        val downloader = KonanPrebuiltsDownloader(
+            fileSystem = fakeFileSystem,
+            downloadPath = "konans".toPath(),
+            testMode = true
+        )
+        downloader.download("1.6.21")
+        assertThat(
+            fakeFileSystem.allPaths
+        ).containsAtLeast(
+            "/konans/llvm-11.1.0-linux-x64-essentials.tar.gz".toPath(),
+            "/konans/apple-llvm-20200714-macos-aarch64-essentials.tar.gz".toPath(),
+            "/konans/apple-llvm-20200714-macos-x64-essentials.tar.gz".toPath(),
+            "/konans/libffi-3.2.1-2-linux-x86-64.tar.gz".toPath(),
+            "/konans/libffi-3.3-1-macos-arm64.tar.gz".toPath(),
+            "/konans/libffi-3.2.1-3-darwin-macos.tar.gz".toPath(),
+            "/konans/x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2.tar.gz".toPath(),
+            "/konans/lldb-4-linux.tar.gz".toPath()
+        )
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/test/kotlin/androidx/build/importMaven/LicenseDownloaderTest.kt b/development/importMaven/src/test/kotlin/androidx/build/importMaven/LicenseDownloaderTest.kt
new file mode 100644
index 0000000..6501e53
--- /dev/null
+++ b/development/importMaven/src/test/kotlin/androidx/build/importMaven/LicenseDownloaderTest.kt
@@ -0,0 +1,78 @@
+/*
+ * 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.build.importMaven
+
+import com.google.common.truth.Truth.assertThat
+import okio.FileSystem
+import okio.Path
+import org.junit.Test
+
+class LicenseDownloaderTest {
+
+    @Test // see: b/130834419, ensure we fallback to Github
+    fun githubLicense() {
+        val licenseDownloader = LicenseDownloader(enableGithubApi = true)
+        val artifactPath = EnvironmentConfig.supportRoot /
+                "../../prebuilts/androidx/external/" /
+                "org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom"
+        val fetchedBytes = FileSystem.SYSTEM.read(
+            artifactPath
+        ) {
+            licenseDownloader.fetchLicenseFromPom(
+                bytes = readByteArray()
+            )
+        }
+        assertThat(
+            fetchedBytes
+        ).isNotNull()
+    }
+
+    @Test // see: b/234867553
+    fun checkLicenseContents() {
+        // download for a know artifact and ensure it matches what we have
+        val artifactPath = EnvironmentConfig.supportRoot /
+                "../../prebuilts/androidx/external/org/jetbrains/kotlin/kotlin-stdlib/1.6.21"
+        checkLocalLicense(
+            localPom = artifactPath / "kotlin-stdlib-1.6.21.pom",
+            localLicense = artifactPath / "LICENSE"
+        )
+    }
+
+    private fun checkLocalLicense(
+        localPom: Path,
+        localLicense: Path
+    ) {
+        val licenseDownloader = LicenseDownloader(enableGithubApi = false)
+        val fetchedBytes = FileSystem.SYSTEM.read(
+            localPom
+        ) {
+            licenseDownloader.fetchLicenseFromPom(
+                bytes = readByteArray()
+            )
+        }?.toString(Charsets.UTF_8)
+        val localBytes = FileSystem.SYSTEM.read(
+            localLicense
+        ) {
+            readUtf8()
+        }
+        assertThat(
+            fetchedBytes
+        ).isEqualTo(
+            localBytes
+        )
+    }
+}
\ No newline at end of file
diff --git a/development/importMaven/src/test/resources/androidx-license.txt b/development/importMaven/src/test/resources/androidx-license.txt
new file mode 120000
index 0000000..385aeaf
--- /dev/null
+++ b/development/importMaven/src/test/resources/androidx-license.txt
@@ -0,0 +1 @@
+../../../../../LICENSE.txt
\ No newline at end of file
diff --git a/development/importMaven/src/test/resources/pom-with-aar-deps.pom b/development/importMaven/src/test/resources/pom-with-aar-deps.pom
new file mode 100644
index 0000000..57d199d
--- /dev/null
+++ b/development/importMaven/src/test/resources/pom-with-aar-deps.pom
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <!-- This module was also published with a richer model, Gradle metadata,  -->
+    <!-- which should be used instead. Do not delete the following line which  -->
+    <!-- is to indicate to Gradle or any Gradle module metadata file consumer  -->
+    <!-- that they should prefer consuming it instead. -->
+    <!-- do_not_remove: published-with-gradle-metadata -->
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>androidx.room</groupId>
+    <artifactId>room-runtime</artifactId>
+    <version>2.5.0-alpha01</version>
+    <packaging>aar</packaging>
+    <name>Android Room-Runtime</name>
+    <description>Android Room-Runtime</description>
+    <url>https://developer.android.com/jetpack/androidx/releases/room#2.5.0-alpha01</url>
+    <inceptionYear>2017</inceptionYear>
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+    <developers>
+        <developer>
+            <name>The Android Open Source Project</name>
+        </developer>
+    </developers>
+    <scm>
+        <connection>scm:git:https://android.googlesource.com/platform/frameworks/support</connection>
+        <url>https://cs.android.com/androidx/platform/frameworks/support</url>
+    </scm>
+    <dependencies>
+        <dependency>
+            <groupId>androidx.room</groupId>
+            <artifactId>room-common</artifactId>
+            <version>[2.5.0-alpha01]</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>androidx.sqlite</groupId>
+            <artifactId>sqlite-framework</artifactId>
+            <version>2.3.0-alpha01</version>
+            <scope>compile</scope>
+            <type>aar</type>
+        </dependency>
+        <dependency>
+            <groupId>androidx.sqlite</groupId>
+            <artifactId>sqlite</artifactId>
+            <version>2.3.0-alpha01</version>
+            <scope>compile</scope>
+            <type>aar</type>
+        </dependency>
+        <dependency>
+            <groupId>androidx.arch.core</groupId>
+            <artifactId>core-runtime</artifactId>
+            <version>2.0.1</version>
+            <scope>runtime</scope>
+            <type>aar</type>
+        </dependency>
+        <dependency>
+            <groupId>androidx.annotation</groupId>
+            <artifactId>annotation-experimental</artifactId>
+            <version>1.1.0-rc01</version>
+            <scope>runtime</scope>
+            <type>aar</type>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/development/referenceDocs/stageReferenceDocsWithDackka.sh b/development/referenceDocs/stageReferenceDocsWithDackka.sh
index 9fd0f9b..0a87b08 100755
--- a/development/referenceDocs/stageReferenceDocsWithDackka.sh
+++ b/development/referenceDocs/stageReferenceDocsWithDackka.sh
@@ -136,9 +136,25 @@
     androidxDackkaDocsZip="dackka-public-docs-${FLAGS_buildId}.zip"
   fi
 
-  /google/data/ro/projects/android/fetch_artifact --bid $FLAGS_buildId --target androidx $androidxJavaDocsZip
-  /google/data/ro/projects/android/fetch_artifact --bid $FLAGS_buildId --target androidx $androidxKotlinDocsZip
-  /google/data/ro/projects/android/fetch_artifact --bid $FLAGS_buildId --target androidx $androidxDackkaDocsZip
+  if (( "${FLAGS_buildId::1}" == "P" )); then
+    /google/data/ro/projects/android/fetch_artifact --bid $FLAGS_buildId --target androidx_incremental incremental/$androidxJavaDocsZip
+    /google/data/ro/projects/android/fetch_artifact --bid $FLAGS_buildId --target androidx_incremental incremental/$androidxKotlinDocsZip
+    /google/data/ro/projects/android/fetch_artifact --bid $FLAGS_buildId --target androidx_incremental incremental/$androidxDackkaDocsZip
+  else
+    /google/data/ro/projects/android/fetch_artifact --bid $FLAGS_buildId --target androidx $androidxJavaDocsZip
+    /google/data/ro/projects/android/fetch_artifact --bid $FLAGS_buildId --target androidx $androidxKotlinDocsZip
+    /google/data/ro/projects/android/fetch_artifact --bid $FLAGS_buildId --target androidx $androidxDackkaDocsZip
+  fi
+
+  # Let's double check we succeeded before continuing
+  if [[ -f "$androidxJavaDocsZip" ]] && [[ -f "$androidxKotlinDocsZip" ]] && [[ -f "$androidxDackkaDocsZip" ]]; then
+    echo "Download completed"
+  else
+    printf "\n"
+    printf "=================================================================== \n"
+    echo "Failed to download doc zip files. Please double check your build ID and try again."
+    exit 1
+  fi
 
   printf "\n"
   printf "=================================================================== \n"
diff --git a/development/update_studio.sh b/development/update_studio.sh
index f17e998..473cc42 100755
--- a/development/update_studio.sh
+++ b/development/update_studio.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 # Get versions
-AGP_VERSION=${1:-7.4.0-alpha05}
-STUDIO_VERSION_STRING=${2:-"Android Studio Electric Eel (2022.1.1) Canary 5"}
+AGP_VERSION=${1:-7.4.0-alpha07}
+STUDIO_VERSION_STRING=${2:-"Android Studio Electric Eel (2022.1.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"`
@@ -43,4 +43,4 @@
 ARTIFACTS_TO_DOWNLOAD+="com.google.testing.platform:core:$ATP_VERSION"
 
 # Download all the artifacts
-./development/importMaven/import_maven_artifacts.py -n "$ARTIFACTS_TO_DOWNLOAD"
\ No newline at end of file
+./development/importMaven/importMaven.sh import-artifact --artifacts "$ARTIFACTS_TO_DOWNLOAD"
\ No newline at end of file
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index 7a8eb1d..f43fd20 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -3,6 +3,10 @@
     id("AndroidXDocsPlugin")
 }
 
+android {
+    namespace "androidx.docs.publicdocs"
+}
+
 dependencies {
     docs("androidx.activity:activity:1.5.0")
     docs("androidx.activity:activity-compose:1.5.0")
@@ -36,7 +40,7 @@
     docs("androidx.camera:camera-extensions:1.2.0-alpha02")
     stubs(fileTree(dir: "../camera/camera-extensions-stub", include: ["camera-extensions-stub.jar"]))
     docs("androidx.camera:camera-lifecycle:1.2.0-alpha02")
-    docs("androidx.camera:camera-mlkit-vision:1.2.0-alpha02")
+    docs("androidx.camera:camera-mlkit-vision:1.2.0-alpha03")
     docs("androidx.camera:camera-previewview:1.1.0-beta02")
     docs("androidx.camera:camera-video:1.2.0-alpha01")
     docs("androidx.camera:camera-view:1.2.0-alpha01")
@@ -45,56 +49,56 @@
     docs("androidx.car.app:app-projected:1.2.0-rc01")
     docs("androidx.car.app:app-testing:1.2.0-rc01")
     docs("androidx.cardview:cardview:1.0.0")
-    docs("androidx.collection:collection:1.2.0")
-    docs("androidx.collection:collection-ktx:1.2.0")
-    docs("androidx.compose.animation:animation:1.2.0-rc02")
-    docs("androidx.compose.animation:animation-core:1.2.0-rc02")
-    docs("androidx.compose.animation:animation-graphics:1.2.0-rc02")
-    samples("androidx.compose.animation:animation-samples:1.2.0-rc02")
-    samples("androidx.compose.animation:animation-core-samples:1.2.0-rc02")
-    samples("androidx.compose.animation:animation-graphics-samples:1.2.0-rc02")
-    docs("androidx.compose.foundation:foundation:1.2.0-rc02")
-    docs("androidx.compose.foundation:foundation-layout:1.2.0-rc02")
-    samples("androidx.compose.foundation:foundation-layout-samples:1.2.0-rc02")
-    samples("androidx.compose.foundation:foundation-samples:1.2.0-rc02")
+    docs("androidx.collection:collection:1.3.0-alpha01")
+    docs("androidx.collection:collection-ktx:1.3.0-alpha01")
+    docs("androidx.compose.animation:animation:1.3.0-alpha01")
+    docs("androidx.compose.animation:animation-core:1.3.0-alpha01")
+    docs("androidx.compose.animation:animation-graphics:1.3.0-alpha01")
+    samples("androidx.compose.animation:animation-samples:1.3.0-alpha01")
+    samples("androidx.compose.animation:animation-core-samples:1.3.0-alpha01")
+    samples("androidx.compose.animation:animation-graphics-samples:1.3.0-alpha01")
+    docs("androidx.compose.foundation:foundation:1.3.0-alpha01")
+    docs("androidx.compose.foundation:foundation-layout:1.3.0-alpha01")
+    samples("androidx.compose.foundation:foundation-layout-samples:1.3.0-alpha01")
+    samples("androidx.compose.foundation:foundation-samples:1.3.0-alpha01")
     docs("androidx.compose.material3:material3:1.0.0-alpha13")
     samples("androidx.compose.material3:material3-samples:1.0.0-alpha13")
     docs("androidx.compose.material3:material3-window-size-class:1.0.0-alpha13")
     samples("androidx.compose.material3:material3-window-size-class-samples:1.0.0-alpha13")
-    docs("androidx.compose.material:material:1.2.0-rc02")
-    docs("androidx.compose.material:material-icons-core:1.2.0-rc02")
-    samples("androidx.compose.material:material-icons-core-samples:1.2.0-rc02")
-    docs("androidx.compose.material:material-ripple:1.2.0-rc02")
-    samples("androidx.compose.material:material-samples:1.2.0-rc02")
-    docs("androidx.compose.runtime:runtime:1.2.0-rc02")
-    docs("androidx.compose.runtime:runtime-livedata:1.2.0-rc02")
-    samples("androidx.compose.runtime:runtime-livedata-samples:1.2.0-rc02")
-    docs("androidx.compose.runtime:runtime-rxjava2:1.2.0-rc02")
-    samples("androidx.compose.runtime:runtime-rxjava2-samples:1.2.0-rc02")
-    docs("androidx.compose.runtime:runtime-rxjava3:1.2.0-rc02")
-    samples("androidx.compose.runtime:runtime-rxjava3-samples:1.2.0-rc02")
-    docs("androidx.compose.runtime:runtime-saveable:1.2.0-rc02")
-    samples("androidx.compose.runtime:runtime-saveable-samples:1.2.0-rc02")
-    samples("androidx.compose.runtime:runtime-samples:1.2.0-rc02")
-    docs("androidx.compose.ui:ui:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-geometry:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-graphics:1.2.0-rc02")
-    samples("androidx.compose.ui:ui-graphics-samples:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-test:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-test-junit4:1.2.0-rc02")
-    samples("androidx.compose.ui:ui-test-samples:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-text:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-text-google-fonts:1.2.0-rc02")
-    samples("androidx.compose.ui:ui-text-samples:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-tooling:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-tooling-data:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-tooling-preview:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-unit:1.2.0-rc02")
-    samples("androidx.compose.ui:ui-unit-samples:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-util:1.2.0-rc02")
-    docs("androidx.compose.ui:ui-viewbinding:1.2.0-rc02")
-    samples("androidx.compose.ui:ui-viewbinding-samples:1.2.0-rc02")
-    samples("androidx.compose.ui:ui-samples:1.2.0-rc02")
+    docs("androidx.compose.material:material:1.3.0-alpha01")
+    docs("androidx.compose.material:material-icons-core:1.3.0-alpha01")
+    samples("androidx.compose.material:material-icons-core-samples:1.3.0-alpha01")
+    docs("androidx.compose.material:material-ripple:1.3.0-alpha01")
+    samples("androidx.compose.material:material-samples:1.3.0-alpha01")
+    docs("androidx.compose.runtime:runtime:1.3.0-alpha01")
+    docs("androidx.compose.runtime:runtime-livedata:1.3.0-alpha01")
+    samples("androidx.compose.runtime:runtime-livedata-samples:1.3.0-alpha01")
+    docs("androidx.compose.runtime:runtime-rxjava2:1.3.0-alpha01")
+    samples("androidx.compose.runtime:runtime-rxjava2-samples:1.3.0-alpha01")
+    docs("androidx.compose.runtime:runtime-rxjava3:1.3.0-alpha01")
+    samples("androidx.compose.runtime:runtime-rxjava3-samples:1.3.0-alpha01")
+    docs("androidx.compose.runtime:runtime-saveable:1.3.0-alpha01")
+    samples("androidx.compose.runtime:runtime-saveable-samples:1.3.0-alpha01")
+    samples("androidx.compose.runtime:runtime-samples:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-geometry:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-graphics:1.3.0-alpha01")
+    samples("androidx.compose.ui:ui-graphics-samples:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-test:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-test-junit4:1.3.0-alpha01")
+    samples("androidx.compose.ui:ui-test-samples:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-text:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-text-google-fonts:1.3.0-alpha01")
+    samples("androidx.compose.ui:ui-text-samples:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-tooling:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-tooling-data:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-tooling-preview:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-unit:1.3.0-alpha01")
+    samples("androidx.compose.ui:ui-unit-samples:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-util:1.3.0-alpha01")
+    docs("androidx.compose.ui:ui-viewbinding:1.3.0-alpha01")
+    samples("androidx.compose.ui:ui-viewbinding-samples:1.3.0-alpha01")
+    samples("androidx.compose.ui:ui-samples:1.3.0-alpha01")
     docs("androidx.concurrent:concurrent-futures:1.1.0")
     docs("androidx.concurrent:concurrent-futures-ktx:1.1.0")
     docs("androidx.contentpager:contentpager:1.0.0")
@@ -103,7 +107,7 @@
     docs("androidx.core:core-google-shortcuts:1.1.0-alpha02")
     docs("androidx.core:core-performance:1.0.0-alpha02")
     samples("androidx.core:core-performance-samples:1.0.0-alpha02")
-    docs("androidx.core:core-remoteviews:1.0.0-alpha03")
+    docs("androidx.core:core-remoteviews:1.0.0-beta01")
     docs("androidx.core:core-role:1.1.0-rc01")
     docs("androidx.core:core-animation:1.0.0-beta01")
     docs("androidx.core:core-animation-testing:1.0.0-alpha02")
@@ -159,25 +163,27 @@
     docs("androidx.leanback:leanback-paging:1.1.0-alpha09")
     docs("androidx.leanback:leanback-preference:1.2.0-alpha02")
     docs("androidx.leanback:leanback-tab:1.1.0-beta01")
-    docs("androidx.lifecycle:lifecycle-common:2.5.0")
-    docs("androidx.lifecycle:lifecycle-common-java8:2.5.0")
+    docs("androidx.lifecycle:lifecycle-common:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-common-java8:2.6.0-alpha01")
     docs("androidx.lifecycle:lifecycle-extensions:2.2.0")
-    docs("androidx.lifecycle:lifecycle-livedata:2.5.0")
-    docs("androidx.lifecycle:lifecycle-livedata-core:2.5.0")
-    docs("androidx.lifecycle:lifecycle-livedata-core-ktx:2.5.0")
-    docs("androidx.lifecycle:lifecycle-livedata-ktx:2.5.0")
-    docs("androidx.lifecycle:lifecycle-process:2.5.0")
-    docs("androidx.lifecycle:lifecycle-reactivestreams:2.5.0")
-    docs("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.5.0")
-    docs("androidx.lifecycle:lifecycle-runtime:2.5.0")
-    docs("androidx.lifecycle:lifecycle-runtime-ktx:2.5.0")
-    docs("androidx.lifecycle:lifecycle-runtime-testing:2.5.0")
-    docs("androidx.lifecycle:lifecycle-service:2.5.0")
-    docs("androidx.lifecycle:lifecycle-viewmodel:2.5.0")
-    docs("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0")
-    samples("androidx.lifecycle:lifecycle-viewmodel-compose-samples:2.5.0")
-    docs("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0")
-    docs("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.5.0")
+    docs("androidx.lifecycle:lifecycle-livedata:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-livedata-core:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-livedata-core-ktx:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-livedata-ktx:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-process:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-reactivestreams:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-runtime:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-runtime-compose:2.6.0-alpha01")
+    samples("androidx.lifecycle:lifecycle-runtime-compose-samples:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-runtime-ktx:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-runtime-testing:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-service:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-viewmodel:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.0-alpha01")
+    samples("androidx.lifecycle:lifecycle-viewmodel-compose-samples:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.0-alpha01")
+    docs("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.0-alpha01")
     docs("androidx.loader:loader:1.1.0")
     docs("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0")
     docs("androidx.media2:media2-common:1.2.1")
@@ -187,20 +193,20 @@
     docs("androidx.media:media:1.6.0")
     docs("androidx.mediarouter:mediarouter:1.3.0")
     docs("androidx.mediarouter:mediarouter-testing:1.3.0")
-    docs("androidx.metrics:metrics-performance:1.0.0-alpha01")
-    docs("androidx.navigation:navigation-common:2.5.0-rc02")
-    docs("androidx.navigation:navigation-common-ktx:2.5.0-rc02")
-    docs("androidx.navigation:navigation-compose:2.5.0-rc02")
-    samples("androidx.navigation:navigation-compose-samples:2.5.0-rc02")
-    docs("androidx.navigation:navigation-dynamic-features-fragment:2.5.0-rc02")
-    docs("androidx.navigation:navigation-dynamic-features-runtime:2.5.0-rc02")
-    docs("androidx.navigation:navigation-fragment:2.5.0-rc02")
-    docs("androidx.navigation:navigation-fragment-ktx:2.5.0-rc02")
-    docs("androidx.navigation:navigation-runtime:2.5.0-rc02")
-    docs("androidx.navigation:navigation-runtime-ktx:2.5.0-rc02")
-    docs("androidx.navigation:navigation-testing:2.5.0-rc02")
-    docs("androidx.navigation:navigation-ui:2.5.0-rc02")
-    docs("androidx.navigation:navigation-ui-ktx:2.5.0-rc02")
+    docs("androidx.metrics:metrics-performance:1.0.0-alpha02")
+    docs("androidx.navigation:navigation-common:2.5.0")
+    docs("androidx.navigation:navigation-common-ktx:2.5.0")
+    docs("androidx.navigation:navigation-compose:2.5.0")
+    samples("androidx.navigation:navigation-compose-samples:2.5.0")
+    docs("androidx.navigation:navigation-dynamic-features-fragment:2.5.0")
+    docs("androidx.navigation:navigation-dynamic-features-runtime:2.5.0")
+    docs("androidx.navigation:navigation-fragment:2.5.0")
+    docs("androidx.navigation:navigation-fragment-ktx:2.5.0")
+    docs("androidx.navigation:navigation-runtime:2.5.0")
+    docs("androidx.navigation:navigation-runtime-ktx:2.5.0")
+    docs("androidx.navigation:navigation-testing:2.5.0")
+    docs("androidx.navigation:navigation-ui:2.5.0")
+    docs("androidx.navigation:navigation-ui-ktx:2.5.0")
     docs("androidx.paging:paging-common:3.2.0-alpha01")
     docs("androidx.paging:paging-common-ktx:3.2.0-alpha01")
     docs("androidx.paging:paging-compose:1.0.0-alpha15")
@@ -220,7 +226,7 @@
     docs("androidx.print:print:1.1.0-beta01")
     docs("androidx.profileinstaller:profileinstaller:1.2.0-rc01")
     docs("androidx.recommendation:recommendation:1.0.0")
-    docs("androidx.recyclerview:recyclerview:1.3.0-alpha02")
+    docs("androidx.recyclerview:recyclerview:1.3.0-beta01")
     docs("androidx.recyclerview:recyclerview-selection:2.0.0-alpha01")
     docs("androidx.remotecallback:remotecallback:1.0.0-alpha02")
     docs("androidx.resourceinspection:resourceinspection-annotation:1.0.1")
@@ -267,17 +273,17 @@
     docs("androidx.versionedparcelable:versionedparcelable:1.1.1")
     docs("androidx.viewpager2:viewpager2:1.1.0-beta01")
     docs("androidx.viewpager:viewpager:1.1.0-alpha01")
-    docs("androidx.wear.compose:compose-foundation:1.0.0-rc01")
-    samples("androidx.wear.compose:compose-foundation-samples:1.0.0-rc01")
-    docs("androidx.wear.compose:compose-material:1.0.0-rc01")
-    samples("androidx.wear.compose:compose-material-samples:1.0.0-rc01")
-    docs("androidx.wear.compose:compose-navigation:1.0.0-rc01")
-    samples("androidx.wear.compose:compose-navigation-samples:1.0.0-rc01")
-    docs("androidx.wear.tiles:tiles:1.1.0-alpha08")
-    docs("androidx.wear.tiles:tiles-material:1.1.0-alpha08")
-    docs("androidx.wear.tiles:tiles-proto:1.1.0-alpha08")
-    docs("androidx.wear.tiles:tiles-renderer:1.1.0-alpha08")
-    docs("androidx.wear.tiles:tiles-testing:1.1.0-alpha08")
+    docs("androidx.wear.compose:compose-foundation:1.1.0-alpha01")
+    samples("androidx.wear.compose:compose-foundation-samples:1.1.0-alpha01")
+    docs("androidx.wear.compose:compose-material:1.1.0-alpha01")
+    samples("androidx.wear.compose:compose-material-samples:1.1.0-alpha01")
+    docs("androidx.wear.compose:compose-navigation:1.1.0-alpha01")
+    samples("androidx.wear.compose:compose-navigation-samples:1.1.0-alpha01")
+    docs("androidx.wear.tiles:tiles:1.1.0-alpha09")
+    docs("androidx.wear.tiles:tiles-material:1.1.0-alpha09")
+    docs("androidx.wear.tiles:tiles-proto:1.1.0-alpha09")
+    docs("androidx.wear.tiles:tiles-renderer:1.1.0-alpha09")
+    docs("androidx.wear.tiles:tiles-testing:1.1.0-alpha09")
     docs("androidx.wear.watchface:watchface:1.1.0")
     docs("androidx.wear.watchface:watchface-client:1.1.0")
     docs("androidx.wear.watchface:watchface-client-guava:1.1.0")
@@ -302,7 +308,7 @@
     docs("androidx.wear:wear-input:1.2.0-alpha02")
     samples("androidx.wear:wear-input-samples:1.2.0-alpha01")
     docs("androidx.wear:wear-input-testing:1.2.0-alpha02")
-    docs("androidx.webkit:webkit:1.5.0-alpha01")
+    docs("androidx.webkit:webkit:1.5.0-beta01")
     docs("androidx.window:window:1.1.0-alpha02")
     stubs(fileTree(dir: "../window/stubs/", include: ["window-sidecar-release-0.1.0-alpha01.aar"]))
     stubs("androidx.window:window-extensions:1.0.0-alpha01")
diff --git a/docs-public/src/main/AndroidManifest.xml b/docs-public/src/main/AndroidManifest.xml
deleted file mode 100644
index c0c456b..0000000
--- a/docs-public/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-  ~ Copyright 2020 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.
-  -->
-<manifest package="androidx.docs.publicdocs"/>
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index c3f41cf..581ad2dc 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -3,6 +3,10 @@
     id("AndroidXDocsPlugin")
 }
 
+android {
+    namespace "androidx.docs.tipoftree"
+}
+
 dependencies {
     docs(project(":activity:activity"))
     docs(project(":activity:activity-compose"))
diff --git a/docs-tip-of-tree/src/main/AndroidManifest.xml b/docs-tip-of-tree/src/main/AndroidManifest.xml
deleted file mode 100644
index bb41812..0000000
--- a/docs-tip-of-tree/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-  ~ Copyright 2020 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.
-  -->
-<manifest package="androidx.docs.tipoftree"/>
diff --git a/emoji/emoji-appcompat/lint-baseline.xml b/emoji/emoji-appcompat/lint-baseline.xml
index 70fc728..bca811a 100644
--- a/emoji/emoji-appcompat/lint-baseline.xml
+++ b/emoji/emoji-appcompat/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
diff --git a/emoji2/emoji2-bundled/lint-baseline.xml b/emoji2/emoji2-bundled/lint-baseline.xml
index b70ef65..ba06e13 100644
--- a/emoji2/emoji2-bundled/lint-baseline.xml
+++ b/emoji2/emoji2-bundled/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/emoji2/emoji2-views-helper/AndroidManifest.xml b/emoji2/emoji2-views-helper/AndroidManifest.xml
deleted file mode 100644
index 95c4426..0000000
--- a/emoji2/emoji2-views-helper/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<manifest />
diff --git a/emoji2/emoji2-views-helper/build.gradle b/emoji2/emoji2-views-helper/build.gradle
index 667f154..c177372 100644
--- a/emoji2/emoji2-views-helper/build.gradle
+++ b/emoji2/emoji2-views-helper/build.gradle
@@ -23,12 +23,6 @@
 }
 
 android {
-    sourceSets {
-        main {
-            // We use a non-standard manifest path.
-            manifest.srcFile 'AndroidManifest.xml'
-        }
-    }
     namespace "androidx.emoji2.viewsintegration"
 }
 
diff --git a/emoji2/emoji2-views-helper/lint-baseline.xml b/emoji2/emoji2-views-helper/lint-baseline.xml
deleted file mode 100644
index ddca6f1..0000000
--- a/emoji2/emoji2-views-helper/lint-baseline.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 19 (current min is 14): `EmojiMetadata`"
-        errorLine1="        final EmojiMetadata metadata = mock(EmojiMetadata.class);"
-        errorLine2="                                            ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `TypefaceEmojiSpan`"
-        errorLine1="        final EmojiSpan span = new TypefaceEmojiSpan(metadata);"
-        errorLine2="                               ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 19 (current min is 14): `EmojiSpan`"
-        errorLine1="        final EmojiSpan[] spans = editable.getSpans(0, 1, EmojiSpan.class);"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiEditableFactoryTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `EmojiTransformationMethod`"
-        errorLine1="        mTransformationMethod = new EmojiTransformationMethod(mWrappedTransformationMethod);"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getTransformation`"
-        errorLine1="        assertNull(mTransformationMethod.getTransformation(null, mView));"
-        errorLine2="                                         ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getTransformation`"
-        errorLine1="        mTransformationMethod.getTransformation(&quot;&quot;, null);"
-        errorLine2="                              ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `EmojiTransformationMethod`"
-        errorLine1="        mTransformationMethod = new EmojiTransformationMethod(null);"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getTransformation`"
-        errorLine1="        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getTransformation`"
-        errorLine1="        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getTransformation`"
-        errorLine1="        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getTransformation`"
-        errorLine1="        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getTransformation`"
-        errorLine1="        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/viewsintegration/EmojiTransformationMethodTest.java"/>
-    </issue>
-
-</issues>
diff --git a/emoji2/emoji2-views-helper/src/androidTest/AndroidManifest.xml b/emoji2/emoji2-views-helper/src/androidTest/AndroidManifest.xml
deleted file mode 100644
index 63f527c..0000000
--- a/emoji2/emoji2-views-helper/src/androidTest/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<manifest>
-
-    <application>
-    </application>
-
-</manifest>
\ No newline at end of file
diff --git a/emoji2/emoji2-views/lint-baseline.xml b/emoji2/emoji2-views/lint-baseline.xml
deleted file mode 100644
index ea225ae..0000000
--- a/emoji2/emoji2-views/lint-baseline.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 15 (current min is 14): `android.view.View#hasOnClickListeners`"
-        errorLine1="        assertTrue(extractButton.hasOnClickListeners());"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 15 (current min is 14): `android.view.View#hasOnClickListeners`"
-        errorLine1="        assertFalse(extractButton.hasOnClickListeners());"
-        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java"/>
-    </issue>
-
-</issues>
diff --git a/emoji2/emoji2-views/src/main/AndroidManifest.xml b/emoji2/emoji2-views/src/main/AndroidManifest.xml
deleted file mode 100644
index 95c4426..0000000
--- a/emoji2/emoji2-views/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<manifest />
diff --git a/emoji2/emoji2/lint-baseline.xml b/emoji2/emoji2/lint-baseline.xml
index 15360c4..b7e9705 100644
--- a/emoji2/emoji2/lint-baseline.xml
+++ b/emoji2/emoji2/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="cli" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
@@ -10,49 +10,4 @@
             file="src/main/java/androidx/emoji2/text/EmojiCompat.java"/>
     </issue>
 
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `create`"
-        errorLine1="            loaderCallback.onLoaded(MetadataRepo.create(mock(Typeface.class)));"
-        errorLine2="                                                 ~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/text/NoFontTestEmojiConfig.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 19 (current min is 14): `EmojiSpan`"
-        errorLine1="        final EmojiSpan span = mock(EmojiSpan.class);"
-        errorLine2="                                    ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 19 (current min is 14): `EmojiSpan`"
-        errorLine1="        EmojiSpan[] spans = spannable.getSpans(0, spannable.length(), EmojiSpan.class);"
-        errorLine2="                                                                      ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 19 (current min is 14): `EmojiSpan`"
-        errorLine1="        final EmojiSpan span = mock(EmojiSpan.class);"
-        errorLine2="                                    ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 19 (current min is 14): `EmojiSpan`"
-        errorLine1="        EmojiSpan[] spans = spannable.getSpans(0, spannable.length(), EmojiSpan.class);"
-        errorLine2="                                                                      ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java"/>
-    </issue>
-
 </issues>
diff --git a/enterprise/enterprise-feedback/lint-baseline.xml b/enterprise/enterprise-feedback/lint-baseline.xml
index 8765ca0..56cd3f8 100644
--- a/enterprise/enterprise-feedback/lint-baseline.xml
+++ b/enterprise/enterprise-feedback/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/BackStackStateTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/BackStackStateTest.kt
index f85cbcc..c3025c4 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/BackStackStateTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/BackStackStateTest.kt
@@ -76,7 +76,7 @@
         }
 
         val stateBundle = Bundle()
-        stateBundle.putParcelable(FragmentManager.FRAGMENT_STATE_TAG, FragmentState(fragment))
+        stateBundle.putParcelable(FragmentStateManager.FRAGMENT_STATE_KEY, FragmentState(fragment))
         fragmentManager.fragmentStore.setSavedState(fragment.mWho, stateBundle)
         val backStackState = BackStackState(
             listOf(fragment.mWho),
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java
index 6d6acd1..5195822 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackState.java
@@ -63,7 +63,8 @@
             Bundle stateBundle = fm.getFragmentStore().setSavedState(fWho, null);
             if (stateBundle != null) {
                 ClassLoader classLoader = fm.getHost().getContext().getClassLoader();
-                FragmentState fs = stateBundle.getParcelable(FragmentManager.FRAGMENT_STATE_TAG);
+                FragmentState fs = stateBundle.getParcelable(
+                        FragmentStateManager.FRAGMENT_STATE_KEY);
                 Fragment fragment = fs.instantiate(fm.getFragmentFactory(), classLoader);
                 fragment.mSavedFragmentState = stateBundle;
 
@@ -71,14 +72,14 @@
                 // non-null Bundle so that developers have a signal for
                 // when the Fragment is being restored
                 if (fragment.mSavedFragmentState.getBundle(
-                        FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG) == null) {
+                        FragmentStateManager.SAVED_INSTANCE_STATE_KEY) == null) {
                     fragment.mSavedFragmentState.putBundle(
-                            FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG,
+                            FragmentStateManager.SAVED_INSTANCE_STATE_KEY,
                             new Bundle());
                 }
 
                 // Instantiate the fragment's arguments
-                Bundle arguments = stateBundle.getBundle(FragmentManager.FRAGMENT_ARGUMENTS_TAG);
+                Bundle arguments = stateBundle.getBundle(FragmentStateManager.ARGUMENTS_KEY);
                 if (arguments != null) {
                     arguments.setClassLoader(classLoader);
                 }
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
index 6237f74..2a5a8e4 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -1962,7 +1962,7 @@
     @CallSuper
     public void onCreate(@Nullable Bundle savedInstanceState) {
         mCalled = true;
-        restoreChildFragmentState(savedInstanceState);
+        restoreChildFragmentState();
         if (!mChildFragmentManager.isStateAtLeast(Fragment.CREATED)) {
             mChildFragmentManager.dispatchCreate();
         }
@@ -1977,15 +1977,13 @@
      * <p><strong>Postcondition:</strong> if there were child fragments to restore,
      * the child FragmentManager will be instantiated and brought to the {@link #CREATED} state.
      * </p>
-     *
-     * @param savedInstanceState the savedInstanceState potentially containing fragment info
      */
-    @SuppressWarnings("deprecation")
-    void restoreChildFragmentState(@Nullable Bundle savedInstanceState) {
-        if (savedInstanceState != null) {
-            Parcelable p = savedInstanceState.getParcelable(FragmentManager.SAVED_STATE_TAG);
-            if (p != null) {
-                mChildFragmentManager.restoreSaveStateInternal(p);
+    void restoreChildFragmentState() {
+        if (mSavedFragmentState != null) {
+            Bundle childFragmentManagerState = mSavedFragmentState.getBundle(
+                    FragmentStateManager.CHILD_FRAGMENT_MANAGER_KEY);
+            if (childFragmentManagerState != null) {
+                mChildFragmentManager.restoreSaveStateInternal(childFragmentManagerState);
                 mChildFragmentManager.dispatchCreate();
             }
         }
@@ -3085,7 +3083,10 @@
                 }
             });
         }
-        mSavedStateRegistryController.performRestore(savedInstanceState);
+        Bundle savedStateRegistryState = mSavedFragmentState != null
+                ? mSavedFragmentState.getBundle(FragmentStateManager.REGISTRY_STATE_KEY)
+                : null;
+        mSavedStateRegistryController.performRestore(savedStateRegistryState);
         onCreate(savedInstanceState);
         mIsCreated = true;
         if (!mCalled) {
@@ -3127,7 +3128,7 @@
         Bundle savedInstanceState = null;
         if (mSavedFragmentState != null) {
             savedInstanceState = mSavedFragmentState.getBundle(
-                    FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG);
+                    FragmentStateManager.SAVED_INSTANCE_STATE_KEY);
         }
         onViewCreated(mView, savedInstanceState);
         mChildFragmentManager.dispatchViewCreated();
@@ -3156,7 +3157,7 @@
             Bundle savedInstanceState = null;
             if (mSavedFragmentState != null) {
                 savedInstanceState = mSavedFragmentState.getBundle(
-                        FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG);
+                        FragmentStateManager.SAVED_INSTANCE_STATE_KEY);
             }
             restoreViewState(savedInstanceState);
         }
@@ -3300,11 +3301,6 @@
 
     void performSaveInstanceState(Bundle outState) {
         onSaveInstanceState(outState);
-        mSavedStateRegistryController.performSave(outState);
-        Parcelable p = mChildFragmentManager.saveAllStateInternal();
-        if (p != null) {
-            outState.putParcelable(FragmentManager.SAVED_STATE_TAG, p);
-        }
     }
 
     @SuppressWarnings("ConstantConditions")
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index 8ead853..6d51810 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -104,15 +104,11 @@
  * {@link FragmentActivity#getSupportFragmentManager}.
  */
 public abstract class FragmentManager implements FragmentResultOwner {
-    static final String SAVED_STATE_TAG = "android:support:fragments";
-    static final String FRAGMENT_MANAGER_STATE_TAG = "state";
-    static final String RESULT_NAME_PREFIX = "result_";
-    static final String FRAGMENT_STATE_TAG = "state";
-    static final String FRAGMENT_NAME_PREFIX = "fragment_";
-    static final String FRAGMENT_SAVED_INSTANCE_STATE_TAG = "savedInstanceState";
-    static final String FRAGMENT_VIEW_STATE_TAG = "viewState";
-    static final String FRAGMENT_VIEW_REGISTRY_STATE_TAG = "viewRegistryState";
-    static final String FRAGMENT_ARGUMENTS_TAG = "arguments";
+    private static final String SAVED_STATE_KEY = "android:support:fragments";
+    private static final String FRAGMENT_MANAGER_STATE_KEY = "state";
+    private static final String RESULT_KEY_PREFIX = "result_";
+    private static final String FRAGMENT_KEY_PREFIX = "fragment_";
+
     private static boolean DEBUG = false;
 
     /** @hide */
@@ -2411,14 +2407,14 @@
             fms.mBackStackStateKeys.addAll(mBackStackStates.keySet());
             fms.mBackStackStates.addAll(mBackStackStates.values());
             fms.mLaunchedFragments = new ArrayList<>(mLaunchedFragments);
-            bundle.putParcelable(FRAGMENT_MANAGER_STATE_TAG, fms);
+            bundle.putParcelable(FRAGMENT_MANAGER_STATE_KEY, fms);
 
             for (String resultName : mResults.keySet()) {
-                bundle.putBundle(RESULT_NAME_PREFIX + resultName, mResults.get(resultName));
+                bundle.putBundle(RESULT_KEY_PREFIX + resultName, mResults.get(resultName));
             }
 
             for (String fWho : savedState.keySet()) {
-                bundle.putBundle(FRAGMENT_NAME_PREFIX + fWho, savedState.get(fWho));
+                bundle.putBundle(FRAGMENT_KEY_PREFIX + fWho, savedState.get(fWho));
             }
         }
 
@@ -2451,11 +2447,11 @@
 
         // Restore the fragment results
         for (String bundleKey : bundle.keySet()) {
-            if (bundleKey.startsWith(RESULT_NAME_PREFIX)) {
+            if (bundleKey.startsWith(RESULT_KEY_PREFIX)) {
                 Bundle savedResult = bundle.getBundle(bundleKey);
                 if (savedResult != null) {
                     savedResult.setClassLoader(mHost.getContext().getClassLoader());
-                    String resultKey = bundleKey.substring(RESULT_NAME_PREFIX.length());
+                    String resultKey = bundleKey.substring(RESULT_KEY_PREFIX.length());
                     mResults.put(resultKey, savedResult);
                 }
             }
@@ -2464,18 +2460,18 @@
         // Restore the saved bundle for all fragments
         HashMap<String, Bundle> allStateBundles = new HashMap<>();
         for (String bundleKey : bundle.keySet()) {
-            if (bundleKey.startsWith(FRAGMENT_NAME_PREFIX)) {
+            if (bundleKey.startsWith(FRAGMENT_KEY_PREFIX)) {
                 Bundle savedFragmentBundle = bundle.getBundle(bundleKey);
                 if (savedFragmentBundle != null) {
                     savedFragmentBundle.setClassLoader(mHost.getContext().getClassLoader());
-                    String fragmentKey = bundleKey.substring(FRAGMENT_NAME_PREFIX.length());
+                    String fragmentKey = bundleKey.substring(FRAGMENT_KEY_PREFIX.length());
                     allStateBundles.put(fragmentKey, savedFragmentBundle);
                 }
             }
         }
         mFragmentStore.restoreSaveState(allStateBundles);
 
-        FragmentManagerState fms = bundle.getParcelable(FRAGMENT_MANAGER_STATE_TAG);
+        FragmentManagerState fms = bundle.getParcelable(FRAGMENT_MANAGER_STATE_KEY);
         if (fms == null) return;
 
         // Build the full list of active fragments, instantiating them from
@@ -2486,7 +2482,8 @@
             Bundle stateBundle = mFragmentStore.setSavedState(who, null);
             if (stateBundle != null) {
                 FragmentStateManager fragmentStateManager;
-                FragmentState fs = stateBundle.getParcelable(FragmentManager.FRAGMENT_STATE_TAG);
+                FragmentState fs = stateBundle.getParcelable(
+                        FragmentStateManager.FRAGMENT_STATE_KEY);
                 Fragment retainedFragment = mNonConfig.findRetainedFragmentByWho(fs.mWho);
                 if (retainedFragment != null) {
                     if (isLoggingEnabled(Log.VERBOSE)) {
@@ -2651,13 +2648,13 @@
         if (mHost instanceof SavedStateRegistryOwner && parent == null) {
             SavedStateRegistry registry =
                     ((SavedStateRegistryOwner) mHost).getSavedStateRegistry();
-            registry.registerSavedStateProvider(SAVED_STATE_TAG, () -> {
+            registry.registerSavedStateProvider(SAVED_STATE_KEY, () -> {
                         return saveAllStateInternal();
                     }
             );
 
             Bundle savedInstanceState = registry
-                    .consumeRestoredStateForKey(SAVED_STATE_TAG);
+                    .consumeRestoredStateForKey(SAVED_STATE_KEY);
             if (savedInstanceState != null) {
                 restoreSaveStateInternal(savedInstanceState);
             }
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
index b3bc44b..0b54927 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
@@ -37,6 +37,14 @@
 class FragmentStateManager {
     private static final String TAG = FragmentManager.TAG;
 
+    static final String FRAGMENT_STATE_KEY = "state";
+    static final String SAVED_INSTANCE_STATE_KEY = "savedInstanceState";
+    static final String REGISTRY_STATE_KEY = "registryState";
+    static final String CHILD_FRAGMENT_MANAGER_KEY = "childFragmentManager";
+    static final String VIEW_STATE_KEY = "viewState";
+    static final String VIEW_REGISTRY_STATE_KEY = "viewRegistryState";
+    static final String ARGUMENTS_KEY = "arguments";
+
     private final FragmentLifecycleCallbacksDispatcher mDispatcher;
     private final FragmentStore mFragmentStore;
     @NonNull
@@ -79,12 +87,12 @@
         mFragmentStore = fragmentStore;
 
         // Instantiate the fragment's library states in FragmentState
-        FragmentState fs = state.getParcelable(FragmentManager.FRAGMENT_STATE_TAG);
+        FragmentState fs = state.getParcelable(FRAGMENT_STATE_KEY);
         mFragment = fs.instantiate(fragmentFactory, classLoader);
         mFragment.mSavedFragmentState = state;
 
         // Instantiate the fragment's arguments
-        Bundle arguments = state.getBundle(FragmentManager.FRAGMENT_ARGUMENTS_TAG);
+        Bundle arguments = state.getBundle(ARGUMENTS_KEY);
         if (arguments != null) {
             arguments.setClassLoader(classLoader);
         }
@@ -121,7 +129,7 @@
         mFragment.mTarget = null;
 
         mFragment.mSavedFragmentState = state;
-        mFragment.mArguments = state.getBundle(FragmentManager.FRAGMENT_ARGUMENTS_TAG);
+        mFragment.mArguments = state.getBundle(ARGUMENTS_KEY);
     }
 
     @NonNull
@@ -391,7 +399,7 @@
             Bundle savedInstanceState = null;
             if (mFragment.mSavedFragmentState != null) {
                 savedInstanceState = mFragment.mSavedFragmentState.getBundle(
-                        FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG);
+                        SAVED_INSTANCE_STATE_KEY);
             }
             mFragment.performCreateView(mFragment.performGetLayoutInflater(
                     savedInstanceState), null, savedInstanceState);
@@ -414,23 +422,22 @@
         }
         mFragment.mSavedFragmentState.setClassLoader(classLoader);
         Bundle savedInstanceState = mFragment.mSavedFragmentState.getBundle(
-                FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG);
+                SAVED_INSTANCE_STATE_KEY);
         if (savedInstanceState == null) {
             // When restoring a Fragment, always ensure we have a
             // non-null Bundle so that developers have a signal for
             // when the Fragment is being restored
-            mFragment.mSavedFragmentState.putBundle(
-                    FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG,
+            mFragment.mSavedFragmentState.putBundle(SAVED_INSTANCE_STATE_KEY,
                     new Bundle());
         }
 
         mFragment.mSavedViewState = mFragment.mSavedFragmentState.getSparseParcelableArray(
-                FragmentManager.FRAGMENT_VIEW_STATE_TAG);
+                VIEW_STATE_KEY);
         mFragment.mSavedViewRegistryState = mFragment.mSavedFragmentState.getBundle(
-                FragmentManager.FRAGMENT_VIEW_REGISTRY_STATE_TAG);
+                VIEW_REGISTRY_STATE_KEY);
 
         FragmentState fs =
-                mFragment.mSavedFragmentState.getParcelable(FragmentManager.FRAGMENT_STATE_TAG);
+                mFragment.mSavedFragmentState.getParcelable(FRAGMENT_STATE_KEY);
         if (fs != null) {
             mFragment.mTargetWho = fs.mTargetWho;
             mFragment.mTargetRequestCode = fs.mTargetRequestCode;
@@ -490,16 +497,17 @@
         }
         Bundle savedInstanceState = null;
         if (mFragment.mSavedFragmentState != null) {
-            savedInstanceState = mFragment.mSavedFragmentState.getBundle(
-                    FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG);
+            savedInstanceState = mFragment.mSavedFragmentState.getBundle(SAVED_INSTANCE_STATE_KEY);
         }
         if (!mFragment.mIsCreated) {
             mDispatcher.dispatchOnFragmentPreCreated(mFragment, savedInstanceState, false);
             mFragment.performCreate(savedInstanceState);
             mDispatcher.dispatchOnFragmentCreated(mFragment, savedInstanceState, false);
         } else {
-            mFragment.restoreChildFragmentState(savedInstanceState);
+            // The retained fragment has already gone through onCreate()
+            // so we move up its state first, then restore any childFragmentManager state
             mFragment.mState = Fragment.CREATED;
+            mFragment.restoreChildFragmentState();
         }
     }
 
@@ -514,8 +522,7 @@
         }
         Bundle savedInstanceState = null;
         if (mFragment.mSavedFragmentState != null) {
-            savedInstanceState = mFragment.mSavedFragmentState.getBundle(
-                    FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG);
+            savedInstanceState = mFragment.mSavedFragmentState.getBundle(SAVED_INSTANCE_STATE_KEY);
         }
         LayoutInflater layoutInflater = mFragment.performGetLayoutInflater(savedInstanceState);
         ViewGroup container = null;
@@ -604,8 +611,7 @@
         }
         Bundle savedInstanceState = null;
         if (mFragment.mSavedFragmentState != null) {
-            savedInstanceState = mFragment.mSavedFragmentState.getBundle(
-                    FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG);
+            savedInstanceState = mFragment.mSavedFragmentState.getBundle(SAVED_INSTANCE_STATE_KEY);
         }
         mFragment.performActivityCreated(savedInstanceState);
         mDispatcher.dispatchOnFragmentActivityCreated(
@@ -674,39 +680,53 @@
     @NonNull
     Bundle saveState() {
         Bundle stateBundle = new Bundle();
+        if (mFragment.mState == Fragment.INITIALIZING) {
+            // We never even got to ATTACHED, but we could still have some state
+            // set by setInitialSavedState so we'll add that to our initial Bundle
+            if (mFragment.mSavedFragmentState != null) {
+                stateBundle.putAll(mFragment.mSavedFragmentState);
+            }
+        }
 
         // Save the library state associated with the Fragment
         FragmentState fs = new FragmentState(mFragment);
-        stateBundle.putParcelable(FragmentManager.FRAGMENT_STATE_TAG, fs);
+        stateBundle.putParcelable(FRAGMENT_STATE_KEY, fs);
 
         // Save the user state associated with the Fragment
         if (mFragment.mState > Fragment.INITIALIZING) {
-            stateBundle.putBundle(FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG,
-                    saveBasicState());
+            Bundle savedInstanceState = new Bundle();
+            mFragment.performSaveInstanceState(savedInstanceState);
+            if (!savedInstanceState.isEmpty()) {
+                stateBundle.putBundle(SAVED_INSTANCE_STATE_KEY, savedInstanceState);
+            }
+            mDispatcher.dispatchOnFragmentSaveInstanceState(mFragment, savedInstanceState, false);
+
+            Bundle savedStateRegistryState = new Bundle();
+            mFragment.mSavedStateRegistryController.performSave(savedStateRegistryState);
+            if (!savedStateRegistryState.isEmpty()) {
+                stateBundle.putBundle(REGISTRY_STATE_KEY, savedStateRegistryState);
+            }
+
+            Bundle childFragmentManagerState =
+                    mFragment.mChildFragmentManager.saveAllStateInternal();
+            if (!childFragmentManagerState.isEmpty()) {
+                stateBundle.putBundle(CHILD_FRAGMENT_MANAGER_KEY, childFragmentManagerState);
+            }
 
             if (mFragment.mView != null) {
                 saveViewState();
             }
             if (mFragment.mSavedViewState != null) {
-                stateBundle.putSparseParcelableArray(FragmentManager.FRAGMENT_VIEW_STATE_TAG,
-                        mFragment.mSavedViewState);
+                stateBundle.putSparseParcelableArray(VIEW_STATE_KEY, mFragment.mSavedViewState);
             }
             if (mFragment.mSavedViewRegistryState != null) {
-                stateBundle.putBundle(FragmentManager.FRAGMENT_VIEW_REGISTRY_STATE_TAG,
-                        mFragment.mSavedViewRegistryState);
-            }
-        } else {
-            if (mFragment.mSavedFragmentState != null) {
-                Bundle previouslySavedState = mFragment.mSavedFragmentState.getBundle(
-                        FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG);
-                if (previouslySavedState != null) {
-                    stateBundle.putBundle(FragmentManager.FRAGMENT_SAVED_INSTANCE_STATE_TAG,
-                            previouslySavedState);
-                }
+                stateBundle.putBundle(VIEW_REGISTRY_STATE_KEY, mFragment.mSavedViewRegistryState);
             }
         }
 
-        stateBundle.putBundle(FragmentManager.FRAGMENT_ARGUMENTS_TAG, mFragment.mArguments);
+        if (mFragment.mArguments != null) {
+            stateBundle.putBundle(ARGUMENTS_KEY, mFragment.mArguments);
+        }
         return stateBundle;
     }
 
@@ -718,19 +738,6 @@
         return null;
     }
 
-    @Nullable
-    private Bundle saveBasicState() {
-        Bundle result = new Bundle();
-
-        mFragment.performSaveInstanceState(result);
-        mDispatcher.dispatchOnFragmentSaveInstanceState(mFragment, result, false);
-        if (result.isEmpty()) {
-            result = null;
-        }
-
-        return result;
-    }
-
     void saveViewState() {
         if (mFragment.mView == null) {
             return;
diff --git a/glance/glance-appwidget/build.gradle b/glance/glance-appwidget/build.gradle
index 92af5d1..6b1a161 100644
--- a/glance/glance-appwidget/build.gradle
+++ b/glance/glance-appwidget/build.gradle
@@ -52,6 +52,7 @@
     implementation("androidx.datastore:datastore-core:1.0.0")
     implementation("androidx.datastore:datastore-preferences-core:1.0.0")
     implementation("androidx.datastore:datastore-preferences:1.0.0")
+    implementation("com.google.android.material:material:1.6.0")
     implementation(project(':core:core-remoteviews'))
     implementation(libs.kotlinStdlib)
 
diff --git a/glance/glance-appwidget/integration-tests/template-demos/src/main/AndroidManifest.xml b/glance/glance-appwidget/integration-tests/template-demos/src/main/AndroidManifest.xml
index a94dd60..4f61b07 100644
--- a/glance/glance-appwidget/integration-tests/template-demos/src/main/AndroidManifest.xml
+++ b/glance/glance-appwidget/integration-tests/template-demos/src/main/AndroidManifest.xml
@@ -13,8 +13,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.glance.appwidget.template.demos">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
     <application
         android:allowBackup="false"
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceAppWidgetTemplates.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceAppWidgetTemplates.kt
index 99844f7..6060207 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceAppWidgetTemplates.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceAppWidgetTemplates.kt
@@ -17,7 +17,6 @@
 package androidx.glance.appwidget.template
 
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.TextUnit
 import androidx.compose.ui.unit.dp
@@ -27,7 +26,6 @@
 import androidx.glance.Image
 import androidx.glance.LocalSize
 import androidx.glance.action.clickable
-import androidx.glance.background
 import androidx.glance.layout.Alignment
 import androidx.glance.layout.Column
 import androidx.glance.layout.Row
@@ -35,6 +33,7 @@
 import androidx.glance.layout.fillMaxWidth
 import androidx.glance.layout.height
 import androidx.glance.layout.width
+import androidx.glance.template.LocalTemplateColors
 import androidx.glance.template.TemplateButton
 import androidx.glance.template.TemplateImageButton
 import androidx.glance.template.TemplateImageWithDescription
@@ -60,7 +59,7 @@
     if (headerIcon == null && header == null && actionButton == null) return
 
     Row(
-        modifier = GlanceModifier.fillMaxWidth().background(Color.Transparent),
+        modifier = GlanceModifier.fillMaxWidth(),
         verticalAlignment = Alignment.CenterVertically
     ) {
         headerIcon?.let {
@@ -79,7 +78,9 @@
             Text(
                 modifier = GlanceModifier.defaultWeight(),
                 text = header.text,
-                style = TextStyle(fontSize = size),
+                style = TextStyle(
+                    fontSize = size,
+                    color = LocalTemplateColors.current.onSurface),
                 maxLines = 1
             )
         }
@@ -102,14 +103,13 @@
 internal fun AppWidgetTextSection(textList: List<TemplateText>) {
     if (textList.isEmpty()) return
 
-    Column(modifier = GlanceModifier.background(Color.Transparent)) {
+    Column() {
         textList.forEachIndexed { index, item ->
             val size = textSize(item.type, DisplaySize.fromDpSize(LocalSize.current))
             Text(
                 item.text,
-                style = TextStyle(fontSize = size),
-                maxLines = maxLines(item.type),
-                modifier = GlanceModifier.background(Color.Transparent)
+                style = TextStyle(fontSize = size, color = LocalTemplateColors.current.onSurface),
+                maxLines = maxLines(item.type)
             )
             if (index < textList.size - 1) {
                 Spacer(modifier = GlanceModifier.height(8.dp))
@@ -129,6 +129,7 @@
     button: TemplateButton,
     glanceModifier: GlanceModifier = GlanceModifier
 ) {
+    val colors = LocalTemplateColors.current
     when (button) {
         is TemplateImageButton -> {
             // TODO: Specify sizing for image button
@@ -140,7 +141,12 @@
             )
         }
         is TemplateTextButton -> {
-            Button(text = button.text, onClick = button.action, modifier = glanceModifier)
+            Button(
+                text = button.text,
+                onClick = button.action,
+                style = TextStyle(color = colors.onPrimary),
+                modifier = glanceModifier
+            )
         }
     }
 }
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceTemplateAppWidget.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceTemplateAppWidget.kt
index 26bd34c..fa89286 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceTemplateAppWidget.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/GlanceTemplateAppWidget.kt
@@ -23,8 +23,10 @@
 import androidx.glance.LocalSize
 import androidx.glance.appwidget.GlanceAppWidget
 import androidx.glance.appwidget.SizeMode
+import androidx.glance.color.dynamicThemeColorProviders
 import androidx.glance.state.GlanceStateDefinition
 import androidx.glance.state.PreferencesGlanceStateDefinition
+import androidx.glance.template.LocalTemplateColors
 import androidx.glance.template.LocalTemplateMode
 import androidx.glance.template.TemplateMode
 
@@ -43,7 +45,13 @@
     final override fun Content() {
         // TODO: Add other local values
         val mode = mode()
-        CompositionLocalProvider(LocalTemplateMode provides mode) { TemplateContent() }
+        val colors = dynamicThemeColorProviders()
+        CompositionLocalProvider(
+            LocalTemplateMode provides mode,
+            LocalTemplateColors provides colors
+        ) {
+            TemplateContent()
+        }
     }
 
     @Composable
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/SingleEntityTemplateLayouts.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/SingleEntityTemplateLayouts.kt
index ed17cce..de9c45f 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/SingleEntityTemplateLayouts.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/template/SingleEntityTemplateLayouts.kt
@@ -17,7 +17,6 @@
 package androidx.glance.appwidget.template
 
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
 import androidx.glance.GlanceModifier
 import androidx.glance.Image
@@ -33,6 +32,7 @@
 import androidx.glance.layout.height
 import androidx.glance.layout.padding
 import androidx.glance.layout.width
+import androidx.glance.template.LocalTemplateColors
 import androidx.glance.template.LocalTemplateMode
 import androidx.glance.template.SingleEntityTemplateData
 import androidx.glance.template.TemplateMode
@@ -56,7 +56,8 @@
 
 @Composable
 private fun WidgetLayoutCollapsed(data: SingleEntityTemplateData) {
-    var modifier = GlanceModifier.fillMaxSize().padding(16.dp).background(Color.White)
+    var modifier = GlanceModifier
+        .fillMaxSize().padding(16.dp).background(LocalTemplateColors.current.surface)
 
     data.image?.let { image ->
         modifier = modifier.background(image.image, ContentScale.Crop)
@@ -70,7 +71,11 @@
 
 @Composable
 private fun WidgetLayoutVertical(data: SingleEntityTemplateData) {
-    Column(modifier = GlanceModifier.fillMaxSize().padding(16.dp).background(Color.White)) {
+
+    Column(modifier = GlanceModifier
+        .fillMaxSize()
+        .padding(16.dp)
+        .background(LocalTemplateColors.current.surface)) {
         data.headerIcon?.let { AppWidgetTemplateHeader(it, data.header) }
         Spacer(modifier = GlanceModifier.height(16.dp))
         data.image?.let { image ->
@@ -92,10 +97,14 @@
 
 @Composable
 private fun WidgetLayoutHorizontal(data: SingleEntityTemplateData) {
-    Row(modifier = GlanceModifier.fillMaxSize().padding(16.dp).background(Color.White)) {
+    Row(modifier = GlanceModifier
+        .fillMaxSize()
+        .padding(16.dp)
+        .background(LocalTemplateColors.current.surface)) {
+
         Column(
             modifier =
-            GlanceModifier.fillMaxHeight().background(Color.Transparent).defaultWeight()
+            GlanceModifier.defaultWeight().fillMaxHeight()
         ) {
             data.headerIcon?.let { AppWidgetTemplateHeader(it, data.header) }
             Spacer(modifier = GlanceModifier.height(16.dp))
diff --git a/glance/glance-wear-tiles/integration-tests/template-demos/src/main/AndroidManifest.xml b/glance/glance-wear-tiles/integration-tests/template-demos/src/main/AndroidManifest.xml
index b551d1f..7ff81be 100644
--- a/glance/glance-wear-tiles/integration-tests/template-demos/src/main/AndroidManifest.xml
+++ b/glance/glance-wear-tiles/integration-tests/template-demos/src/main/AndroidManifest.xml
@@ -13,8 +13,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.glance.wear.tiles.template.demos">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
     <uses-feature android:name="android.hardware.type.watch" />
     <meta-data android:name="com.google.android.wearable.standalone" android:value="true" />
diff --git a/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt b/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt
index 823f7c9..f086c17 100644
--- a/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt
+++ b/glance/glance-wear-tiles/src/test/kotlin/androidx/glance/wear/tiles/GlanceTileServiceTest.kt
@@ -150,8 +150,8 @@
         val tile = tileFuture.await()
 
         val resourcesIds = arrayOf(
-            "android_" + ovalBitmapHashCode,
-            "android_" + R.drawable.ic_launcher_background
+            "android_" + R.drawable.ic_launcher_background,
+            "android_" + ovalBitmapHashCode
         )
 
         val resourcesVersion = Arrays.hashCode(resourcesIds).toString()
diff --git a/glance/glance/api/current.txt b/glance/glance/api/current.txt
index 50713bd..70c8b44 100644
--- a/glance/glance/api/current.txt
+++ b/glance/glance/api/current.txt
@@ -146,6 +146,69 @@
 
 }
 
+package androidx.glance.color {
+
+  public final class ColorProviders {
+    ctor public ColorProviders(androidx.glance.unit.ColorProvider primary, androidx.glance.unit.ColorProvider onPrimary, androidx.glance.unit.ColorProvider primaryContainer, androidx.glance.unit.ColorProvider onPrimaryContainer, androidx.glance.unit.ColorProvider secondary, androidx.glance.unit.ColorProvider onSecondary, androidx.glance.unit.ColorProvider secondaryContainer, androidx.glance.unit.ColorProvider onSecondaryContainer, androidx.glance.unit.ColorProvider tertiary, androidx.glance.unit.ColorProvider onTertiary, androidx.glance.unit.ColorProvider tertiaryContainer, androidx.glance.unit.ColorProvider onTertiaryContainer, androidx.glance.unit.ColorProvider error, androidx.glance.unit.ColorProvider errorContainer, androidx.glance.unit.ColorProvider onError, androidx.glance.unit.ColorProvider onErrorContainer, androidx.glance.unit.ColorProvider background, androidx.glance.unit.ColorProvider onBackground, androidx.glance.unit.ColorProvider surface, androidx.glance.unit.ColorProvider onSurface, androidx.glance.unit.ColorProvider surfaceVariant, androidx.glance.unit.ColorProvider onSurfaceVariant, androidx.glance.unit.ColorProvider outline, androidx.glance.unit.ColorProvider inverseOnSurface, androidx.glance.unit.ColorProvider inverseSurface, androidx.glance.unit.ColorProvider inversePrimary);
+    method public androidx.glance.unit.ColorProvider getBackground();
+    method public androidx.glance.unit.ColorProvider getError();
+    method public androidx.glance.unit.ColorProvider getErrorContainer();
+    method public androidx.glance.unit.ColorProvider getInverseOnSurface();
+    method public androidx.glance.unit.ColorProvider getInversePrimary();
+    method public androidx.glance.unit.ColorProvider getInverseSurface();
+    method public androidx.glance.unit.ColorProvider getOnBackground();
+    method public androidx.glance.unit.ColorProvider getOnError();
+    method public androidx.glance.unit.ColorProvider getOnErrorContainer();
+    method public androidx.glance.unit.ColorProvider getOnPrimary();
+    method public androidx.glance.unit.ColorProvider getOnPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSecondary();
+    method public androidx.glance.unit.ColorProvider getOnSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSurface();
+    method public androidx.glance.unit.ColorProvider getOnSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getOnTertiary();
+    method public androidx.glance.unit.ColorProvider getOnTertiaryContainer();
+    method public androidx.glance.unit.ColorProvider getOutline();
+    method public androidx.glance.unit.ColorProvider getPrimary();
+    method public androidx.glance.unit.ColorProvider getPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getSecondary();
+    method public androidx.glance.unit.ColorProvider getSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getSurface();
+    method public androidx.glance.unit.ColorProvider getSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getTertiary();
+    method public androidx.glance.unit.ColorProvider getTertiaryContainer();
+    property public final androidx.glance.unit.ColorProvider background;
+    property public final androidx.glance.unit.ColorProvider error;
+    property public final androidx.glance.unit.ColorProvider errorContainer;
+    property public final androidx.glance.unit.ColorProvider inverseOnSurface;
+    property public final androidx.glance.unit.ColorProvider inversePrimary;
+    property public final androidx.glance.unit.ColorProvider inverseSurface;
+    property public final androidx.glance.unit.ColorProvider onBackground;
+    property public final androidx.glance.unit.ColorProvider onError;
+    property public final androidx.glance.unit.ColorProvider onErrorContainer;
+    property public final androidx.glance.unit.ColorProvider onPrimary;
+    property public final androidx.glance.unit.ColorProvider onPrimaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSecondary;
+    property public final androidx.glance.unit.ColorProvider onSecondaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSurface;
+    property public final androidx.glance.unit.ColorProvider onSurfaceVariant;
+    property public final androidx.glance.unit.ColorProvider onTertiary;
+    property public final androidx.glance.unit.ColorProvider onTertiaryContainer;
+    property public final androidx.glance.unit.ColorProvider outline;
+    property public final androidx.glance.unit.ColorProvider primary;
+    property public final androidx.glance.unit.ColorProvider primaryContainer;
+    property public final androidx.glance.unit.ColorProvider secondary;
+    property public final androidx.glance.unit.ColorProvider secondaryContainer;
+    property public final androidx.glance.unit.ColorProvider surface;
+    property public final androidx.glance.unit.ColorProvider surfaceVariant;
+    property public final androidx.glance.unit.ColorProvider tertiary;
+    property public final androidx.glance.unit.ColorProvider tertiaryContainer;
+  }
+
+  public final class ColorProvidersKt {
+  }
+
+}
+
 package androidx.glance.layout {
 
   public final class Alignment {
@@ -340,7 +403,9 @@
 package androidx.glance.template {
 
   public final class CompositionLocalsKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> getLocalTemplateColors();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> LocalTemplateColors;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
   }
 
diff --git a/glance/glance/api/public_plus_experimental_current.txt b/glance/glance/api/public_plus_experimental_current.txt
index 50713bd..70c8b44 100644
--- a/glance/glance/api/public_plus_experimental_current.txt
+++ b/glance/glance/api/public_plus_experimental_current.txt
@@ -146,6 +146,69 @@
 
 }
 
+package androidx.glance.color {
+
+  public final class ColorProviders {
+    ctor public ColorProviders(androidx.glance.unit.ColorProvider primary, androidx.glance.unit.ColorProvider onPrimary, androidx.glance.unit.ColorProvider primaryContainer, androidx.glance.unit.ColorProvider onPrimaryContainer, androidx.glance.unit.ColorProvider secondary, androidx.glance.unit.ColorProvider onSecondary, androidx.glance.unit.ColorProvider secondaryContainer, androidx.glance.unit.ColorProvider onSecondaryContainer, androidx.glance.unit.ColorProvider tertiary, androidx.glance.unit.ColorProvider onTertiary, androidx.glance.unit.ColorProvider tertiaryContainer, androidx.glance.unit.ColorProvider onTertiaryContainer, androidx.glance.unit.ColorProvider error, androidx.glance.unit.ColorProvider errorContainer, androidx.glance.unit.ColorProvider onError, androidx.glance.unit.ColorProvider onErrorContainer, androidx.glance.unit.ColorProvider background, androidx.glance.unit.ColorProvider onBackground, androidx.glance.unit.ColorProvider surface, androidx.glance.unit.ColorProvider onSurface, androidx.glance.unit.ColorProvider surfaceVariant, androidx.glance.unit.ColorProvider onSurfaceVariant, androidx.glance.unit.ColorProvider outline, androidx.glance.unit.ColorProvider inverseOnSurface, androidx.glance.unit.ColorProvider inverseSurface, androidx.glance.unit.ColorProvider inversePrimary);
+    method public androidx.glance.unit.ColorProvider getBackground();
+    method public androidx.glance.unit.ColorProvider getError();
+    method public androidx.glance.unit.ColorProvider getErrorContainer();
+    method public androidx.glance.unit.ColorProvider getInverseOnSurface();
+    method public androidx.glance.unit.ColorProvider getInversePrimary();
+    method public androidx.glance.unit.ColorProvider getInverseSurface();
+    method public androidx.glance.unit.ColorProvider getOnBackground();
+    method public androidx.glance.unit.ColorProvider getOnError();
+    method public androidx.glance.unit.ColorProvider getOnErrorContainer();
+    method public androidx.glance.unit.ColorProvider getOnPrimary();
+    method public androidx.glance.unit.ColorProvider getOnPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSecondary();
+    method public androidx.glance.unit.ColorProvider getOnSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSurface();
+    method public androidx.glance.unit.ColorProvider getOnSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getOnTertiary();
+    method public androidx.glance.unit.ColorProvider getOnTertiaryContainer();
+    method public androidx.glance.unit.ColorProvider getOutline();
+    method public androidx.glance.unit.ColorProvider getPrimary();
+    method public androidx.glance.unit.ColorProvider getPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getSecondary();
+    method public androidx.glance.unit.ColorProvider getSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getSurface();
+    method public androidx.glance.unit.ColorProvider getSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getTertiary();
+    method public androidx.glance.unit.ColorProvider getTertiaryContainer();
+    property public final androidx.glance.unit.ColorProvider background;
+    property public final androidx.glance.unit.ColorProvider error;
+    property public final androidx.glance.unit.ColorProvider errorContainer;
+    property public final androidx.glance.unit.ColorProvider inverseOnSurface;
+    property public final androidx.glance.unit.ColorProvider inversePrimary;
+    property public final androidx.glance.unit.ColorProvider inverseSurface;
+    property public final androidx.glance.unit.ColorProvider onBackground;
+    property public final androidx.glance.unit.ColorProvider onError;
+    property public final androidx.glance.unit.ColorProvider onErrorContainer;
+    property public final androidx.glance.unit.ColorProvider onPrimary;
+    property public final androidx.glance.unit.ColorProvider onPrimaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSecondary;
+    property public final androidx.glance.unit.ColorProvider onSecondaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSurface;
+    property public final androidx.glance.unit.ColorProvider onSurfaceVariant;
+    property public final androidx.glance.unit.ColorProvider onTertiary;
+    property public final androidx.glance.unit.ColorProvider onTertiaryContainer;
+    property public final androidx.glance.unit.ColorProvider outline;
+    property public final androidx.glance.unit.ColorProvider primary;
+    property public final androidx.glance.unit.ColorProvider primaryContainer;
+    property public final androidx.glance.unit.ColorProvider secondary;
+    property public final androidx.glance.unit.ColorProvider secondaryContainer;
+    property public final androidx.glance.unit.ColorProvider surface;
+    property public final androidx.glance.unit.ColorProvider surfaceVariant;
+    property public final androidx.glance.unit.ColorProvider tertiary;
+    property public final androidx.glance.unit.ColorProvider tertiaryContainer;
+  }
+
+  public final class ColorProvidersKt {
+  }
+
+}
+
 package androidx.glance.layout {
 
   public final class Alignment {
@@ -340,7 +403,9 @@
 package androidx.glance.template {
 
   public final class CompositionLocalsKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> getLocalTemplateColors();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> LocalTemplateColors;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
   }
 
diff --git a/glance/glance/api/restricted_current.txt b/glance/glance/api/restricted_current.txt
index 50713bd..70c8b44 100644
--- a/glance/glance/api/restricted_current.txt
+++ b/glance/glance/api/restricted_current.txt
@@ -146,6 +146,69 @@
 
 }
 
+package androidx.glance.color {
+
+  public final class ColorProviders {
+    ctor public ColorProviders(androidx.glance.unit.ColorProvider primary, androidx.glance.unit.ColorProvider onPrimary, androidx.glance.unit.ColorProvider primaryContainer, androidx.glance.unit.ColorProvider onPrimaryContainer, androidx.glance.unit.ColorProvider secondary, androidx.glance.unit.ColorProvider onSecondary, androidx.glance.unit.ColorProvider secondaryContainer, androidx.glance.unit.ColorProvider onSecondaryContainer, androidx.glance.unit.ColorProvider tertiary, androidx.glance.unit.ColorProvider onTertiary, androidx.glance.unit.ColorProvider tertiaryContainer, androidx.glance.unit.ColorProvider onTertiaryContainer, androidx.glance.unit.ColorProvider error, androidx.glance.unit.ColorProvider errorContainer, androidx.glance.unit.ColorProvider onError, androidx.glance.unit.ColorProvider onErrorContainer, androidx.glance.unit.ColorProvider background, androidx.glance.unit.ColorProvider onBackground, androidx.glance.unit.ColorProvider surface, androidx.glance.unit.ColorProvider onSurface, androidx.glance.unit.ColorProvider surfaceVariant, androidx.glance.unit.ColorProvider onSurfaceVariant, androidx.glance.unit.ColorProvider outline, androidx.glance.unit.ColorProvider inverseOnSurface, androidx.glance.unit.ColorProvider inverseSurface, androidx.glance.unit.ColorProvider inversePrimary);
+    method public androidx.glance.unit.ColorProvider getBackground();
+    method public androidx.glance.unit.ColorProvider getError();
+    method public androidx.glance.unit.ColorProvider getErrorContainer();
+    method public androidx.glance.unit.ColorProvider getInverseOnSurface();
+    method public androidx.glance.unit.ColorProvider getInversePrimary();
+    method public androidx.glance.unit.ColorProvider getInverseSurface();
+    method public androidx.glance.unit.ColorProvider getOnBackground();
+    method public androidx.glance.unit.ColorProvider getOnError();
+    method public androidx.glance.unit.ColorProvider getOnErrorContainer();
+    method public androidx.glance.unit.ColorProvider getOnPrimary();
+    method public androidx.glance.unit.ColorProvider getOnPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSecondary();
+    method public androidx.glance.unit.ColorProvider getOnSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getOnSurface();
+    method public androidx.glance.unit.ColorProvider getOnSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getOnTertiary();
+    method public androidx.glance.unit.ColorProvider getOnTertiaryContainer();
+    method public androidx.glance.unit.ColorProvider getOutline();
+    method public androidx.glance.unit.ColorProvider getPrimary();
+    method public androidx.glance.unit.ColorProvider getPrimaryContainer();
+    method public androidx.glance.unit.ColorProvider getSecondary();
+    method public androidx.glance.unit.ColorProvider getSecondaryContainer();
+    method public androidx.glance.unit.ColorProvider getSurface();
+    method public androidx.glance.unit.ColorProvider getSurfaceVariant();
+    method public androidx.glance.unit.ColorProvider getTertiary();
+    method public androidx.glance.unit.ColorProvider getTertiaryContainer();
+    property public final androidx.glance.unit.ColorProvider background;
+    property public final androidx.glance.unit.ColorProvider error;
+    property public final androidx.glance.unit.ColorProvider errorContainer;
+    property public final androidx.glance.unit.ColorProvider inverseOnSurface;
+    property public final androidx.glance.unit.ColorProvider inversePrimary;
+    property public final androidx.glance.unit.ColorProvider inverseSurface;
+    property public final androidx.glance.unit.ColorProvider onBackground;
+    property public final androidx.glance.unit.ColorProvider onError;
+    property public final androidx.glance.unit.ColorProvider onErrorContainer;
+    property public final androidx.glance.unit.ColorProvider onPrimary;
+    property public final androidx.glance.unit.ColorProvider onPrimaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSecondary;
+    property public final androidx.glance.unit.ColorProvider onSecondaryContainer;
+    property public final androidx.glance.unit.ColorProvider onSurface;
+    property public final androidx.glance.unit.ColorProvider onSurfaceVariant;
+    property public final androidx.glance.unit.ColorProvider onTertiary;
+    property public final androidx.glance.unit.ColorProvider onTertiaryContainer;
+    property public final androidx.glance.unit.ColorProvider outline;
+    property public final androidx.glance.unit.ColorProvider primary;
+    property public final androidx.glance.unit.ColorProvider primaryContainer;
+    property public final androidx.glance.unit.ColorProvider secondary;
+    property public final androidx.glance.unit.ColorProvider secondaryContainer;
+    property public final androidx.glance.unit.ColorProvider surface;
+    property public final androidx.glance.unit.ColorProvider surfaceVariant;
+    property public final androidx.glance.unit.ColorProvider tertiary;
+    property public final androidx.glance.unit.ColorProvider tertiaryContainer;
+  }
+
+  public final class ColorProvidersKt {
+  }
+
+}
+
 package androidx.glance.layout {
 
   public final class Alignment {
@@ -340,7 +403,9 @@
 package androidx.glance.template {
 
   public final class CompositionLocalsKt {
+    method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> getLocalTemplateColors();
     method public static androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> getLocalTemplateMode();
+    property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.color.ColorProviders> LocalTemplateColors;
     property public static final androidx.compose.runtime.ProvidableCompositionLocal<androidx.glance.template.TemplateMode> LocalTemplateMode;
   }
 
diff --git a/glance/glance/build.gradle b/glance/glance/build.gradle
index 804fbf6..6b5a6fd 100644
--- a/glance/glance/build.gradle
+++ b/glance/glance/build.gradle
@@ -38,6 +38,7 @@
     api("androidx.datastore:datastore-preferences:1.0.0")
 
     implementation("androidx.annotation:annotation:1.1.0")
+    implementation("com.google.android.material:material:1.6.0")
     implementation(libs.kotlinStdlib)
     implementation(project(":compose:runtime:runtime"))
 
@@ -60,6 +61,7 @@
 android {
     // Use Robolectric 4.+
     testOptions.unitTests.includeAndroidResources = true
+    resourcePrefix "glance_"
     namespace "androidx.glance"
 }
 
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/color/ColorProviders.kt b/glance/glance/src/androidMain/kotlin/androidx/glance/color/ColorProviders.kt
new file mode 100644
index 0000000..46ba370
--- /dev/null
+++ b/glance/glance/src/androidMain/kotlin/androidx/glance/color/ColorProviders.kt
@@ -0,0 +1,187 @@
+/*
+ * 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.glance.color
+
+import androidx.annotation.RestrictTo
+import androidx.glance.R
+import androidx.glance.unit.ColorProvider
+
+/**
+ * Holds a set of Glance specific [ColorProvider] that can be used to represent a Material 3 color
+ * scheme.
+ */
+class ColorProviders(
+    val primary: ColorProvider,
+    val onPrimary: ColorProvider,
+    val primaryContainer: ColorProvider,
+    val onPrimaryContainer: ColorProvider,
+    val secondary: ColorProvider,
+    val onSecondary: ColorProvider,
+    val secondaryContainer: ColorProvider,
+    val onSecondaryContainer: ColorProvider,
+    val tertiary: ColorProvider,
+    val onTertiary: ColorProvider,
+    val tertiaryContainer: ColorProvider,
+    val onTertiaryContainer: ColorProvider,
+    val error: ColorProvider,
+    val errorContainer: ColorProvider,
+    val onError: ColorProvider,
+    val onErrorContainer: ColorProvider,
+    val background: ColorProvider,
+    val onBackground: ColorProvider,
+    val surface: ColorProvider,
+    val onSurface: ColorProvider,
+    val surfaceVariant: ColorProvider,
+    val onSurfaceVariant: ColorProvider,
+    val outline: ColorProvider,
+    val inverseOnSurface: ColorProvider,
+    val inverseSurface: ColorProvider,
+    val inversePrimary: ColorProvider
+    ) {
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as ColorProviders
+
+        if (primary != other.primary) return false
+        if (onPrimary != other.onPrimary) return false
+        if (primaryContainer != other.primaryContainer) return false
+        if (onPrimaryContainer != other.onPrimaryContainer) return false
+        if (secondary != other.secondary) return false
+        if (onSecondary != other.onSecondary) return false
+        if (secondaryContainer != other.secondaryContainer) return false
+        if (onSecondaryContainer != other.onSecondaryContainer) return false
+        if (tertiary != other.tertiary) return false
+        if (onTertiary != other.onTertiary) return false
+        if (tertiaryContainer != other.tertiaryContainer) return false
+        if (onTertiaryContainer != other.onTertiaryContainer) return false
+        if (error != other.error) return false
+        if (errorContainer != other.errorContainer) return false
+        if (onError != other.onError) return false
+        if (onErrorContainer != other.onErrorContainer) return false
+        if (background != other.background) return false
+        if (onBackground != other.onBackground) return false
+        if (surface != other.surface) return false
+        if (onSurface != other.onSurface) return false
+        if (surfaceVariant != other.surfaceVariant) return false
+        if (onSurfaceVariant != other.onSurfaceVariant) return false
+        if (outline != other.outline) return false
+        if (inverseOnSurface != other.inverseOnSurface) return false
+        if (inverseSurface != other.inverseSurface) return false
+        if (inversePrimary != other.inversePrimary) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = primary.hashCode()
+        result = 31 * result + onPrimary.hashCode()
+        result = 31 * result + primaryContainer.hashCode()
+        result = 31 * result + onPrimaryContainer.hashCode()
+        result = 31 * result + secondary.hashCode()
+        result = 31 * result + onSecondary.hashCode()
+        result = 31 * result + secondaryContainer.hashCode()
+        result = 31 * result + onSecondaryContainer.hashCode()
+        result = 31 * result + tertiary.hashCode()
+        result = 31 * result + onTertiary.hashCode()
+        result = 31 * result + tertiaryContainer.hashCode()
+        result = 31 * result + onTertiaryContainer.hashCode()
+        result = 31 * result + error.hashCode()
+        result = 31 * result + errorContainer.hashCode()
+        result = 31 * result + onError.hashCode()
+        result = 31 * result + onErrorContainer.hashCode()
+        result = 31 * result + background.hashCode()
+        result = 31 * result + onBackground.hashCode()
+        result = 31 * result + surface.hashCode()
+        result = 31 * result + onSurface.hashCode()
+        result = 31 * result + surfaceVariant.hashCode()
+        result = 31 * result + onSurfaceVariant.hashCode()
+        result = 31 * result + outline.hashCode()
+        result = 31 * result + inverseOnSurface.hashCode()
+        result = 31 * result + inverseSurface.hashCode()
+        result = 31 * result + inversePrimary.hashCode()
+        return result
+    }
+
+    override fun toString(): String {
+        return "ColorProviders(primary=$primary," +
+            " onPrimary=$onPrimary, " +
+            "primaryContainer=$primaryContainer, " +
+            "onPrimaryContainer=$onPrimaryContainer, " +
+            "secondary=$secondary, " +
+            "onSecondary=$onSecondary, " +
+            "secondaryContainer=$secondaryContainer, " +
+            "onSecondaryContainer=$onSecondaryContainer, " +
+            "tertiary=$tertiary, " +
+            "onTertiary=$onTertiary, " +
+            "tertiaryContainer=$tertiaryContainer, " +
+            "onTertiaryContainer=$onTertiaryContainer, " +
+            "error=$error, " +
+            "errorContainer=$errorContainer, " +
+            "onError=$onError, " +
+            "onErrorContainer=$onErrorContainer, " +
+            "background=$background, " +
+            "onBackground=$onBackground, " +
+            "surface=$surface, " +
+            "onSurface=$onSurface, " +
+            "surfaceVariant=$surfaceVariant, " +
+            "onSurfaceVariant=$onSurfaceVariant, " +
+            "outline=$outline, " +
+            "inverseOnSurface=$inverseOnSurface, " +
+            "inverseSurface=$inverseSurface, " +
+            "inversePrimary=$inversePrimary)"
+    }
+}
+
+/**
+ * Creates a set of color providers that represents a Material 3 style dynamic color theme. On
+ * devices that support it, this theme is derived from the user specific platform colors, on other
+ * devices this falls back to the Material baseline theme.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun dynamicThemeColorProviders(): ColorProviders {
+    return ColorProviders(
+        primary = ColorProvider(R.color.glance_colorPrimary),
+        onPrimary = ColorProvider(R.color.glance_colorOnPrimary),
+        primaryContainer = ColorProvider(R.color.glance_colorPrimaryContainer),
+        onPrimaryContainer = ColorProvider(R.color.glance_colorOnPrimaryContainer),
+        secondary = ColorProvider(R.color.glance_colorSecondary),
+        onSecondary = ColorProvider(R.color.glance_colorOnSecondary),
+        secondaryContainer = ColorProvider(R.color.glance_colorSecondaryContainer),
+        onSecondaryContainer = ColorProvider(R.color.glance_colorOnSecondaryContainer),
+        tertiary = ColorProvider(R.color.glance_colorTertiary),
+        onTertiary = ColorProvider(R.color.glance_colorOnTertiary),
+        tertiaryContainer = ColorProvider(R.color.glance_colorTertiaryContainer),
+        onTertiaryContainer = ColorProvider(R.color.glance_colorOnTertiaryContainer),
+        error = ColorProvider(R.color.glance_colorError),
+        errorContainer = ColorProvider(R.color.glance_colorErrorContainer),
+        onError = ColorProvider(R.color.glance_colorOnError),
+        onErrorContainer = ColorProvider(R.color.glance_colorOnErrorContainer),
+        background = ColorProvider(R.color.glance_colorBackground),
+        onBackground = ColorProvider(R.color.glance_colorOnBackground),
+        surface = ColorProvider(R.color.glance_colorSurface),
+        onSurface = ColorProvider(R.color.glance_colorOnSurface),
+        surfaceVariant = ColorProvider(R.color.glance_colorSurfaceVariant),
+        onSurfaceVariant = ColorProvider(R.color.glance_colorOnSurfaceVariant),
+        outline = ColorProvider(R.color.glance_colorOutline),
+        inverseOnSurface = ColorProvider(R.color.glance_colorOnSurfaceInverse),
+        inverseSurface = ColorProvider(R.color.glance_colorSurfaceInverse),
+        inversePrimary = ColorProvider(R.color.glance_colorPrimaryInverse),
+    )
+}
diff --git a/glance/glance/src/androidMain/kotlin/androidx/glance/template/CompositionLocals.kt b/glance/glance/src/androidMain/kotlin/androidx/glance/template/CompositionLocals.kt
index c6c6b70..4cf1991 100644
--- a/glance/glance/src/androidMain/kotlin/androidx/glance/template/CompositionLocals.kt
+++ b/glance/glance/src/androidMain/kotlin/androidx/glance/template/CompositionLocals.kt
@@ -17,5 +17,10 @@
 package androidx.glance.template
 
 import androidx.compose.runtime.compositionLocalOf
+import androidx.glance.color.ColorProviders
 
-val LocalTemplateMode = compositionLocalOf<TemplateMode> { error("Not provided") }
\ No newline at end of file
+val LocalTemplateMode = compositionLocalOf<TemplateMode> { error("No template mode provided") }
+
+val LocalTemplateColors = compositionLocalOf<ColorProviders> {
+    error("No template colors provided")
+}
diff --git a/glance/glance/src/androidMain/res/values-night-v31/colors.xml b/glance/glance/src/androidMain/res/values-night-v31/colors.xml
new file mode 100644
index 0000000..36c885b
--- /dev/null
+++ b/glance/glance/src/androidMain/res/values-night-v31/colors.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<resources>
+    <color name="glance_colorPrimary">@color/m3_sys_color_dynamic_dark_primary</color>
+    <color name="glance_colorOnPrimary">@color/m3_sys_color_dynamic_dark_on_primary</color>
+    <color name="glance_colorPrimaryInverse">@color/m3_sys_color_dynamic_dark_inverse_primary</color>
+    <color name="glance_colorPrimaryContainer">@color/m3_sys_color_dynamic_dark_primary_container</color>
+    <color name="glance_colorOnPrimaryContainer">@color/m3_sys_color_dynamic_dark_on_primary_container</color>
+    <color name="glance_colorSecondary">@color/m3_sys_color_dynamic_dark_secondary</color>
+    <color name="glance_colorOnSecondary">@color/m3_sys_color_dynamic_dark_on_secondary</color>
+    <color name="glance_colorSecondaryContainer">@color/m3_sys_color_dynamic_dark_secondary_container</color>
+    <color name="glance_colorOnSecondaryContainer">@color/m3_sys_color_dynamic_dark_on_secondary_container</color>
+    <color name="glance_colorTertiary">@color/m3_sys_color_dynamic_dark_tertiary</color>
+    <color name="glance_colorOnTertiary">@color/m3_sys_color_dynamic_dark_on_tertiary</color>
+    <color name="glance_colorTertiaryContainer">@color/m3_sys_color_dynamic_dark_tertiary_container</color>
+    <color name="glance_colorOnTertiaryContainer">@color/m3_sys_color_dynamic_dark_on_tertiary_container</color>
+    <color name="glance_colorBackground">@color/m3_sys_color_dynamic_dark_background</color>
+    <color name="glance_colorOnBackground">@color/m3_sys_color_dynamic_dark_on_background</color>
+    <color name="glance_colorSurface">@color/m3_sys_color_dynamic_dark_surface</color>
+    <color name="glance_colorOnSurface">@color/m3_sys_color_dynamic_dark_on_surface</color>
+    <color name="glance_colorSurfaceVariant">@color/m3_sys_color_dynamic_dark_surface_variant</color>
+    <color name="glance_colorOnSurfaceVariant">@color/m3_sys_color_dynamic_dark_on_surface_variant</color>
+    <color name="glance_colorSurfaceInverse">@color/m3_sys_color_dynamic_dark_inverse_surface</color>
+    <color name="glance_colorOnSurfaceInverse">@color/m3_sys_color_dynamic_dark_inverse_on_surface</color>
+    <color name="glance_colorOutline">@color/m3_sys_color_dynamic_dark_outline</color>
+    <color name="glance_colorError">@color/m3_sys_color_dark_error</color>
+    <color name="glance_colorOnError">@color/m3_sys_color_dark_on_error</color>
+    <color name="glance_colorErrorContainer">@color/m3_sys_color_dark_error_container</color>
+    <color name="glance_colorOnErrorContainer">@color/m3_sys_color_dark_on_error_container</color>
+
+    <!--<color name="textColorPrimary">@color/m3_dynamic_dark_default_color_primary_text</color>
+    <color name="textColorPrimaryInverse">@color/m3_dynamic_default_color_primary_text</color>
+    <color name="textColorSecondary">@color/m3_dynamic_dark_default_color_secondary_text</color>
+    <color name="textColorSecondaryInverse">@color/m3_dynamic_default_color_secondary_text</color>-->
+</resources>
\ No newline at end of file
diff --git a/glance/glance/src/androidMain/res/values-night/colors.xml b/glance/glance/src/androidMain/res/values-night/colors.xml
new file mode 100644
index 0000000..5f432cb
--- /dev/null
+++ b/glance/glance/src/androidMain/res/values-night/colors.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<resources>
+    <color name="glance_colorPrimary">@color/m3_sys_color_dark_primary</color>
+    <color name="glance_colorOnPrimary">@color/m3_sys_color_dark_on_primary</color>
+    <color name="glance_colorPrimaryInverse">@color/m3_sys_color_dark_inverse_primary</color>
+    <color name="glance_colorPrimaryContainer">@color/m3_sys_color_dark_primary_container</color>
+    <color name="glance_colorOnPrimaryContainer">@color/m3_sys_color_dark_on_primary_container</color>
+    <color name="glance_colorSecondary">@color/m3_sys_color_dark_secondary</color>
+    <color name="glance_colorOnSecondary">@color/m3_sys_color_dark_on_secondary</color>
+    <color name="glance_colorSecondaryContainer">@color/m3_sys_color_dark_secondary_container</color>
+    <color name="glance_colorOnSecondaryContainer">@color/m3_sys_color_dark_on_secondary_container</color>
+    <color name="glance_colorTertiary">@color/m3_sys_color_dark_tertiary</color>
+    <color name="glance_colorOnTertiary">@color/m3_sys_color_dark_on_tertiary</color>
+    <color name="glance_colorTertiaryContainer">@color/m3_sys_color_dark_tertiary_container</color>
+    <color name="glance_colorOnTertiaryContainer">@color/m3_sys_color_dark_on_tertiary_container</color>
+    <color name="glance_colorBackground">@color/m3_sys_color_dark_background</color>
+    <color name="glance_colorOnBackground">@color/m3_sys_color_dark_on_background</color>
+    <color name="glance_colorSurface">@color/m3_sys_color_dark_surface</color>
+    <color name="glance_colorOnSurface">@color/m3_sys_color_dark_on_surface</color>
+    <color name="glance_colorSurfaceVariant">@color/m3_sys_color_dark_surface_variant</color>
+    <color name="glance_colorOnSurfaceVariant">@color/m3_sys_color_dark_on_surface_variant</color>
+    <color name="glance_colorSurfaceInverse">@color/m3_sys_color_dark_inverse_surface</color>
+    <color name="glance_colorOnSurfaceInverse">@color/m3_sys_color_dark_inverse_on_surface</color>
+    <color name="glance_colorOutline">@color/m3_sys_color_dark_outline</color>
+    <color name="glance_colorError">@color/m3_sys_color_dark_error</color>
+    <color name="glance_colorOnError">@color/m3_sys_color_dark_on_error</color>
+    <color name="glance_colorErrorContainer">@color/m3_sys_color_dark_error_container</color>
+    <color name="glance_colorOnErrorContainer">@color/m3_sys_color_dark_on_error_container</color>
+
+    <!--<color name="textColorPrimary">@color/m3_dark_default_color_primary_text</color>
+    <color name="textColorPrimaryInverse">@color/m3_default_color_primary_text</color>
+    <color name="textColorSecondary">@color/m3_dark_default_color_secondary_text</color>
+    <color name="textColorSecondaryInverse">@color/m3_default_color_secondary_text</color>-->
+</resources>
\ No newline at end of file
diff --git a/glance/glance/src/androidMain/res/values-v31/colors.xml b/glance/glance/src/androidMain/res/values-v31/colors.xml
new file mode 100644
index 0000000..e6cac06
--- /dev/null
+++ b/glance/glance/src/androidMain/res/values-v31/colors.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<resources>
+    <color name="glance_colorPrimary">@color/m3_sys_color_dynamic_light_primary</color>
+    <color name="glance_colorOnPrimary">@color/m3_sys_color_dynamic_light_on_primary</color>
+    <color name="glance_colorPrimaryInverse">@color/m3_sys_color_dynamic_light_inverse_primary</color>
+    <color name="glance_colorPrimaryContainer">@color/m3_sys_color_dynamic_light_primary_container</color>
+    <color name="glance_colorOnPrimaryContainer">@color/m3_sys_color_dynamic_light_on_primary_container</color>
+    <color name="glance_colorSecondary">@color/m3_sys_color_dynamic_light_secondary</color>
+    <color name="glance_colorOnSecondary">@color/m3_sys_color_dynamic_light_on_secondary</color>
+    <color name="glance_colorSecondaryContainer">@color/m3_sys_color_dynamic_light_secondary_container</color>
+    <color name="glance_colorOnSecondaryContainer">@color/m3_sys_color_dynamic_light_on_secondary_container</color>
+    <color name="glance_colorTertiary">@color/m3_sys_color_dynamic_light_tertiary</color>
+    <color name="glance_colorOnTertiary">@color/m3_sys_color_dynamic_light_on_tertiary</color>
+    <color name="glance_colorTertiaryContainer">@color/m3_sys_color_dynamic_light_tertiary_container</color>
+    <color name="glance_colorOnTertiaryContainer">@color/m3_sys_color_dynamic_light_on_tertiary_container</color>
+    <color name="glance_colorBackground">@color/m3_sys_color_dynamic_light_background</color>
+    <color name="glance_colorOnBackground">@color/m3_sys_color_dynamic_light_on_background</color>
+    <color name="glance_colorSurface">@color/m3_sys_color_dynamic_light_surface</color>
+    <color name="glance_colorOnSurface">@color/m3_sys_color_dynamic_light_on_surface</color>
+    <color name="glance_colorSurfaceVariant">@color/m3_sys_color_dynamic_light_surface_variant</color>
+    <color name="glance_colorOnSurfaceVariant">@color/m3_sys_color_dynamic_light_on_surface_variant</color>
+    <color name="glance_colorSurfaceInverse">@color/m3_sys_color_dynamic_light_inverse_surface</color>
+    <color name="glance_colorOnSurfaceInverse">@color/m3_sys_color_dynamic_light_inverse_on_surface</color>
+    <color name="glance_colorOutline">@color/m3_sys_color_dynamic_light_outline</color>
+    <color name="glance_colorError">@color/m3_sys_color_light_error</color>
+    <color name="glance_colorOnError">@color/m3_sys_color_light_on_error</color>
+    <color name="glance_colorErrorContainer">@color/m3_sys_color_light_error_container</color>
+    <color name="glance_colorOnErrorContainer">@color/m3_sys_color_light_on_error_container</color>
+
+    <!--<color name="textColorPrimary">@color/m3_dynamic_default_color_primary_text</color>
+    <color name="textColorPrimaryInverse">@color/m3_dynamic_dark_default_color_primary_text</color>
+    <color name="textColorSecondary">@color/m3_dynamic_default_color_secondary_text</color>
+    <color name="textColorSecondaryInverse">@color/m3_dynamic_dark_default_color_secondary_text
+    </color>-->
+</resources>
\ No newline at end of file
diff --git a/glance/glance/src/androidMain/res/values/colors.xml b/glance/glance/src/androidMain/res/values/colors.xml
new file mode 100644
index 0000000..8fd372f
--- /dev/null
+++ b/glance/glance/src/androidMain/res/values/colors.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<resources>
+    <color name="glance_colorPrimary">@color/m3_sys_color_light_primary</color>
+    <color name="glance_colorOnPrimary">@color/m3_sys_color_light_on_primary</color>
+    <color name="glance_colorPrimaryInverse">@color/m3_sys_color_light_inverse_primary</color>
+    <color name="glance_colorPrimaryContainer">@color/m3_sys_color_light_primary_container</color>
+    <color name="glance_colorOnPrimaryContainer">@color/m3_sys_color_light_on_primary_container</color>
+    <color name="glance_colorSecondary">@color/m3_sys_color_light_secondary</color>
+    <color name="glance_colorOnSecondary">@color/m3_sys_color_light_on_secondary</color>
+    <color name="glance_colorSecondaryContainer">@color/m3_sys_color_light_secondary_container</color>
+    <color name="glance_colorOnSecondaryContainer">@color/m3_sys_color_light_on_secondary_container</color>
+    <color name="glance_colorTertiary">@color/m3_sys_color_light_tertiary</color>
+    <color name="glance_colorOnTertiary">@color/m3_sys_color_light_on_tertiary</color>
+    <color name="glance_colorTertiaryContainer">@color/m3_sys_color_light_tertiary_container</color>
+    <color name="glance_colorOnTertiaryContainer">@color/m3_sys_color_light_on_tertiary_container</color>
+    <color name="glance_colorBackground">@color/m3_sys_color_light_background</color>
+    <color name="glance_colorOnBackground">@color/m3_sys_color_light_on_background</color>
+    <color name="glance_colorSurface">@color/m3_sys_color_light_surface</color>
+    <color name="glance_colorOnSurface">@color/m3_sys_color_light_on_surface</color>
+    <color name="glance_colorSurfaceVariant">@color/m3_sys_color_light_surface_variant</color>
+    <color name="glance_colorOnSurfaceVariant">@color/m3_sys_color_light_on_surface_variant</color>
+    <color name="glance_colorSurfaceInverse">@color/m3_sys_color_light_inverse_surface</color>
+    <color name="glance_colorOnSurfaceInverse">@color/m3_sys_color_light_inverse_on_surface</color>
+    <color name="glance_colorOutline">@color/m3_sys_color_light_outline</color>
+    <color name="glance_colorError">@color/m3_sys_color_light_error</color>
+    <color name="glance_colorOnError">@color/m3_sys_color_light_on_error</color>
+    <color name="glance_colorErrorContainer">@color/m3_sys_color_light_error_container</color>
+    <color name="glance_colorOnErrorContainer">@color/m3_sys_color_light_on_error_container</color>
+
+    <!--<color name="textColorPrimary">@color/m3_default_color_primary_text</color>
+    <color name="textColorPrimaryInverse">@color/m3_dark_default_color_primary_text</color>
+    <color name="textColorSecondary">@color/m3_default_color_secondary_text</color>
+    <color name="textColorSecondaryInverse">@color/m3_dark_default_color_secondary_text</color>-->
+</resources>
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 1f6319c..1095b04 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.4.0-alpha05"
+androidGradlePlugin = "7.4.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.4.0-alpha05"
+androidLint = "30.4.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 = "2022.1.1.5"
+androidStudio = "2022.1.1.7"
 # -----------------------------------------------------------------------------
 
 androidGradlePluginMin = "7.0.4"
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index c3f07ca..05902486 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,3 +3,4 @@
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
 distributionUrl=../../../../tools/external/gradle/gradle-7.5-rc-2-bin.zip
+distributionSha256Sum=ba761aa1563f5d893d1a6e7ddca48bbdc4385fdd527974e6472b873b7eae9a32
diff --git a/gridlayout/gridlayout/lint-baseline.xml b/gridlayout/gridlayout/lint-baseline.xml
index 140efae..d089f4c 100644
--- a/gridlayout/gridlayout/lint-baseline.xml
+++ b/gridlayout/gridlayout/lint-baseline.xml
@@ -1,14 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 21 (current min is 14): `new android.widget.FrameLayout`"
-        errorLine1="        super(context, attrs, defStyleAttr, defStyleRes);"
-        errorLine2="        ~~~~~">
-        <location
-            file="src/androidTest/java/androidx/gridlayout/widget/TestContentView.java"/>
-    </issue>
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
diff --git a/health/health-connect-client-proto/build.gradle b/health/health-connect-client-proto/build.gradle
new file mode 100644
index 0000000..a234b6f
--- /dev/null
+++ b/health/health-connect-client-proto/build.gradle
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+import androidx.build.Publish
+
+/*
+ * All the following content was derived from :datastore:datastore-core.
+ */
+
+plugins {
+    id("AndroidXPlugin")
+    id("java-library")
+    id("com.google.protobuf")
+}
+
+dependencies {
+    implementation(libs.protobufLite)
+}
+
+sourceSets {
+    main.java.srcDirs += "$buildDir/generated/source/proto"
+}
+
+protobuf {
+    protoc {
+        artifact = libs.protobufCompiler.get()
+    }
+
+    // Generates the java proto-lite code for the protos in this project. See
+    // https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
+    // for more information.
+    generateProtoTasks {
+        all().each { task ->
+            project.tasks.named("sourceJar").configure {
+                it.dependsOn(task)
+            }
+            project.tasks.named("runErrorProne").configure {
+                it.dependsOn(task)
+            }
+            project.tasks.named("lint").configure {
+                it.dependsOn(task)
+                it.enabled = false
+            }
+            project.tasks.named("lintAnalyze").configure {
+                it.dependsOn(task)
+                it.enabled = false
+            }
+            task.builtins {
+                java {
+                    option "lite"
+                }
+            }
+        }
+    }
+}
+
+// Create export artifact for for JarJaring
+def preferencesProtoJarJarTask = tasks.register("exportJar", Jar) {
+    archiveBaseName.set("export")
+    from(sourceSets.main.output)
+    // The proto-lite dependency includes .proto files, which are not used by datastore. When apps
+    // depend on datastore as well as proto-lite directly, these files conflict since jarjar only
+    // renames the java classes. Remove them here since they are unused.
+    exclude("**/*.proto")
+
+    from(zipTree(configurations.detachedConfiguration(
+            dependencies.create(libs.protobufLite.get())).getSingleFile()))
+}
+
+def jarjarConf = configurations.register("export")
+artifacts.add(jarjarConf.name, preferencesProtoJarJarTask.flatMap { it.archiveFile })
+
+androidx {
+    name = "AndroidX Health Connect Client Proto"
+    publish = Publish.NONE
+    mavenGroup = LibraryGroups.HEALTH
+    inceptionYear = "2022"
+    description = "Proto files for health-connect-client"
+}
diff --git a/health/health-connect-client/src/main/proto/change.proto b/health/health-connect-client-proto/src/main/proto/change.proto
similarity index 100%
rename from health/health-connect-client/src/main/proto/change.proto
rename to health/health-connect-client-proto/src/main/proto/change.proto
diff --git a/health/health-connect-client/src/main/proto/data.proto b/health/health-connect-client-proto/src/main/proto/data.proto
similarity index 100%
rename from health/health-connect-client/src/main/proto/data.proto
rename to health/health-connect-client-proto/src/main/proto/data.proto
diff --git a/health/health-connect-client/src/main/proto/error.proto b/health/health-connect-client-proto/src/main/proto/error.proto
similarity index 100%
rename from health/health-connect-client/src/main/proto/error.proto
rename to health/health-connect-client-proto/src/main/proto/error.proto
diff --git a/health/health-connect-client/src/main/proto/permission.proto b/health/health-connect-client-proto/src/main/proto/permission.proto
similarity index 100%
rename from health/health-connect-client/src/main/proto/permission.proto
rename to health/health-connect-client-proto/src/main/proto/permission.proto
diff --git a/health/health-connect-client/src/main/proto/request.proto b/health/health-connect-client-proto/src/main/proto/request.proto
similarity index 100%
rename from health/health-connect-client/src/main/proto/request.proto
rename to health/health-connect-client-proto/src/main/proto/request.proto
diff --git a/health/health-connect-client/src/main/proto/response.proto b/health/health-connect-client-proto/src/main/proto/response.proto
similarity index 100%
rename from health/health-connect-client/src/main/proto/response.proto
rename to health/health-connect-client-proto/src/main/proto/response.proto
diff --git a/health/health-connect-client/src/main/proto/time.proto b/health/health-connect-client-proto/src/main/proto/time.proto
similarity index 100%
rename from health/health-connect-client/src/main/proto/time.proto
rename to health/health-connect-client-proto/src/main/proto/time.proto
diff --git a/health/health-connect-client/api/current.txt b/health/health-connect-client/api/current.txt
index 100f938..3a5df3a 100644
--- a/health/health-connect-client/api/current.txt
+++ b/health/health-connect-client/api/current.txt
@@ -230,13 +230,13 @@
   }
 
   public final class BodyFatRecord implements androidx.health.connect.client.records.Record {
-    ctor public BodyFatRecord(int percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public BodyFatRecord(androidx.health.connect.client.units.Percentage percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public int getPercentage();
+    method public androidx.health.connect.client.units.Percentage getPercentage();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final int percentage;
+    property public final androidx.health.connect.client.units.Percentage percentage;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -910,13 +910,13 @@
   }
 
   public final class OxygenSaturationRecord implements androidx.health.connect.client.records.Record {
-    ctor public OxygenSaturationRecord(int percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public OxygenSaturationRecord(androidx.health.connect.client.units.Percentage percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public int getPercentage();
+    method public androidx.health.connect.client.units.Percentage getPercentage();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final int percentage;
+    property public final androidx.health.connect.client.units.Percentage percentage;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -1064,37 +1064,37 @@
     field public static final String UNKNOWN = "unknown";
   }
 
-  public final class Speed {
-    ctor public Speed(java.time.Instant time, @FloatRange(from=0.0, to=1000000.0) double metersPerSecond);
-    method public double getMetersPerSecond();
-    method public java.time.Instant getTime();
-    property public final double metersPerSecond;
-    property public final java.time.Instant time;
-  }
-
   public final class SpeedRecord implements androidx.health.connect.client.records.Record {
-    ctor public SpeedRecord(java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, java.util.List<androidx.health.connect.client.records.Speed> samples, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public SpeedRecord(java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, java.util.List<androidx.health.connect.client.records.SpeedRecord.Sample> samples, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public java.util.List<androidx.health.connect.client.records.Speed> getSamples();
+    method public java.util.List<androidx.health.connect.client.records.SpeedRecord.Sample> getSamples();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public java.util.List<androidx.health.connect.client.records.Speed> samples;
+    property public java.util.List<androidx.health.connect.client.records.SpeedRecord.Sample> samples;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
     field public static final androidx.health.connect.client.records.SpeedRecord.Companion Companion;
-    field public static final androidx.health.connect.client.aggregate.AggregateMetric<java.lang.Double> SPEED_AVG;
-    field public static final androidx.health.connect.client.aggregate.AggregateMetric<java.lang.Double> SPEED_MAX;
-    field public static final androidx.health.connect.client.aggregate.AggregateMetric<java.lang.Double> SPEED_MIN;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.Velocity> SPEED_AVG;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.Velocity> SPEED_MAX;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.Velocity> SPEED_MIN;
   }
 
   public static final class SpeedRecord.Companion {
   }
 
+  public static final class SpeedRecord.Sample {
+    ctor public SpeedRecord.Sample(java.time.Instant time, androidx.health.connect.client.units.Velocity speed);
+    method public androidx.health.connect.client.units.Velocity getSpeed();
+    method public java.time.Instant getTime();
+    property public final androidx.health.connect.client.units.Velocity speed;
+    property public final java.time.Instant time;
+  }
+
   public final class StepsCadence {
     ctor public StepsCadence(java.time.Instant time, @FloatRange(from=0.0, to=10000.0) double rate);
     method public double getRate();
@@ -1493,6 +1493,16 @@
   public final class MassKt {
   }
 
+  public final class Percentage implements java.lang.Comparable<androidx.health.connect.client.units.Percentage> {
+    ctor public Percentage(double value);
+    method public int compareTo(androidx.health.connect.client.units.Percentage other);
+    method public double getValue();
+    property public final double value;
+  }
+
+  public final class PercentageKt {
+  }
+
   public final class Power implements java.lang.Comparable<androidx.health.connect.client.units.Power> {
     method public int compareTo(androidx.health.connect.client.units.Power other);
     method public double getKilocaloriesPerDay();
@@ -1546,6 +1556,29 @@
   public final class TemperatureKt {
   }
 
+  public final class Velocity implements java.lang.Comparable<androidx.health.connect.client.units.Velocity> {
+    method public int compareTo(androidx.health.connect.client.units.Velocity other);
+    method public double getKilometersPerHour();
+    method public double getMetersPerSecond();
+    method public double getMilesPerHour();
+    method public static androidx.health.connect.client.units.Velocity kilometersPerHour(double value);
+    method public static androidx.health.connect.client.units.Velocity metersPerSecond(double value);
+    method public static androidx.health.connect.client.units.Velocity milesPerHour(double value);
+    property public final double inKilometersPerHour;
+    property public final double inMetersPerSecond;
+    property public final double inMilesPerHour;
+    field public static final androidx.health.connect.client.units.Velocity.Companion Companion;
+  }
+
+  public static final class Velocity.Companion {
+    method public androidx.health.connect.client.units.Velocity kilometersPerHour(double value);
+    method public androidx.health.connect.client.units.Velocity metersPerSecond(double value);
+    method public androidx.health.connect.client.units.Velocity milesPerHour(double value);
+  }
+
+  public final class VelocityKt {
+  }
+
   public final class Volume implements java.lang.Comparable<androidx.health.connect.client.units.Volume> {
     method public int compareTo(androidx.health.connect.client.units.Volume other);
     method public double getLiters();
diff --git a/health/health-connect-client/api/public_plus_experimental_current.txt b/health/health-connect-client/api/public_plus_experimental_current.txt
index 100f938..3a5df3a 100644
--- a/health/health-connect-client/api/public_plus_experimental_current.txt
+++ b/health/health-connect-client/api/public_plus_experimental_current.txt
@@ -230,13 +230,13 @@
   }
 
   public final class BodyFatRecord implements androidx.health.connect.client.records.Record {
-    ctor public BodyFatRecord(int percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public BodyFatRecord(androidx.health.connect.client.units.Percentage percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public int getPercentage();
+    method public androidx.health.connect.client.units.Percentage getPercentage();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final int percentage;
+    property public final androidx.health.connect.client.units.Percentage percentage;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -910,13 +910,13 @@
   }
 
   public final class OxygenSaturationRecord implements androidx.health.connect.client.records.Record {
-    ctor public OxygenSaturationRecord(int percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public OxygenSaturationRecord(androidx.health.connect.client.units.Percentage percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public int getPercentage();
+    method public androidx.health.connect.client.units.Percentage getPercentage();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final int percentage;
+    property public final androidx.health.connect.client.units.Percentage percentage;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -1064,37 +1064,37 @@
     field public static final String UNKNOWN = "unknown";
   }
 
-  public final class Speed {
-    ctor public Speed(java.time.Instant time, @FloatRange(from=0.0, to=1000000.0) double metersPerSecond);
-    method public double getMetersPerSecond();
-    method public java.time.Instant getTime();
-    property public final double metersPerSecond;
-    property public final java.time.Instant time;
-  }
-
   public final class SpeedRecord implements androidx.health.connect.client.records.Record {
-    ctor public SpeedRecord(java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, java.util.List<androidx.health.connect.client.records.Speed> samples, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public SpeedRecord(java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, java.util.List<androidx.health.connect.client.records.SpeedRecord.Sample> samples, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public java.util.List<androidx.health.connect.client.records.Speed> getSamples();
+    method public java.util.List<androidx.health.connect.client.records.SpeedRecord.Sample> getSamples();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public java.util.List<androidx.health.connect.client.records.Speed> samples;
+    property public java.util.List<androidx.health.connect.client.records.SpeedRecord.Sample> samples;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
     field public static final androidx.health.connect.client.records.SpeedRecord.Companion Companion;
-    field public static final androidx.health.connect.client.aggregate.AggregateMetric<java.lang.Double> SPEED_AVG;
-    field public static final androidx.health.connect.client.aggregate.AggregateMetric<java.lang.Double> SPEED_MAX;
-    field public static final androidx.health.connect.client.aggregate.AggregateMetric<java.lang.Double> SPEED_MIN;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.Velocity> SPEED_AVG;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.Velocity> SPEED_MAX;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.Velocity> SPEED_MIN;
   }
 
   public static final class SpeedRecord.Companion {
   }
 
+  public static final class SpeedRecord.Sample {
+    ctor public SpeedRecord.Sample(java.time.Instant time, androidx.health.connect.client.units.Velocity speed);
+    method public androidx.health.connect.client.units.Velocity getSpeed();
+    method public java.time.Instant getTime();
+    property public final androidx.health.connect.client.units.Velocity speed;
+    property public final java.time.Instant time;
+  }
+
   public final class StepsCadence {
     ctor public StepsCadence(java.time.Instant time, @FloatRange(from=0.0, to=10000.0) double rate);
     method public double getRate();
@@ -1493,6 +1493,16 @@
   public final class MassKt {
   }
 
+  public final class Percentage implements java.lang.Comparable<androidx.health.connect.client.units.Percentage> {
+    ctor public Percentage(double value);
+    method public int compareTo(androidx.health.connect.client.units.Percentage other);
+    method public double getValue();
+    property public final double value;
+  }
+
+  public final class PercentageKt {
+  }
+
   public final class Power implements java.lang.Comparable<androidx.health.connect.client.units.Power> {
     method public int compareTo(androidx.health.connect.client.units.Power other);
     method public double getKilocaloriesPerDay();
@@ -1546,6 +1556,29 @@
   public final class TemperatureKt {
   }
 
+  public final class Velocity implements java.lang.Comparable<androidx.health.connect.client.units.Velocity> {
+    method public int compareTo(androidx.health.connect.client.units.Velocity other);
+    method public double getKilometersPerHour();
+    method public double getMetersPerSecond();
+    method public double getMilesPerHour();
+    method public static androidx.health.connect.client.units.Velocity kilometersPerHour(double value);
+    method public static androidx.health.connect.client.units.Velocity metersPerSecond(double value);
+    method public static androidx.health.connect.client.units.Velocity milesPerHour(double value);
+    property public final double inKilometersPerHour;
+    property public final double inMetersPerSecond;
+    property public final double inMilesPerHour;
+    field public static final androidx.health.connect.client.units.Velocity.Companion Companion;
+  }
+
+  public static final class Velocity.Companion {
+    method public androidx.health.connect.client.units.Velocity kilometersPerHour(double value);
+    method public androidx.health.connect.client.units.Velocity metersPerSecond(double value);
+    method public androidx.health.connect.client.units.Velocity milesPerHour(double value);
+  }
+
+  public final class VelocityKt {
+  }
+
   public final class Volume implements java.lang.Comparable<androidx.health.connect.client.units.Volume> {
     method public int compareTo(androidx.health.connect.client.units.Volume other);
     method public double getLiters();
diff --git a/health/health-connect-client/api/restricted_current.txt b/health/health-connect-client/api/restricted_current.txt
index d597095..ed5ecdb 100644
--- a/health/health-connect-client/api/restricted_current.txt
+++ b/health/health-connect-client/api/restricted_current.txt
@@ -230,13 +230,13 @@
   }
 
   public final class BodyFatRecord implements androidx.health.connect.client.records.InstantaneousRecord {
-    ctor public BodyFatRecord(int percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public BodyFatRecord(androidx.health.connect.client.units.Percentage percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public int getPercentage();
+    method public androidx.health.connect.client.units.Percentage getPercentage();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final int percentage;
+    property public final androidx.health.connect.client.units.Percentage percentage;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -928,13 +928,13 @@
   }
 
   public final class OxygenSaturationRecord implements androidx.health.connect.client.records.InstantaneousRecord {
-    ctor public OxygenSaturationRecord(int percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public OxygenSaturationRecord(androidx.health.connect.client.units.Percentage percentage, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public int getPercentage();
+    method public androidx.health.connect.client.units.Percentage getPercentage();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final int percentage;
+    property public final androidx.health.connect.client.units.Percentage percentage;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -1087,37 +1087,37 @@
     field public static final String UNKNOWN = "unknown";
   }
 
-  public final class Speed {
-    ctor public Speed(java.time.Instant time, @FloatRange(from=0.0, to=1000000.0) double metersPerSecond);
-    method public double getMetersPerSecond();
-    method public java.time.Instant getTime();
-    property public final double metersPerSecond;
-    property public final java.time.Instant time;
-  }
-
-  public final class SpeedRecord implements androidx.health.connect.client.records.SeriesRecord<androidx.health.connect.client.records.Speed> {
-    ctor public SpeedRecord(java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, java.util.List<androidx.health.connect.client.records.Speed> samples, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+  public final class SpeedRecord implements androidx.health.connect.client.records.SeriesRecord<androidx.health.connect.client.records.SpeedRecord.Sample> {
+    ctor public SpeedRecord(java.time.Instant startTime, java.time.ZoneOffset? startZoneOffset, java.time.Instant endTime, java.time.ZoneOffset? endZoneOffset, java.util.List<androidx.health.connect.client.records.SpeedRecord.Sample> samples, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public java.time.Instant getEndTime();
     method public java.time.ZoneOffset? getEndZoneOffset();
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public java.util.List<androidx.health.connect.client.records.Speed> getSamples();
+    method public java.util.List<androidx.health.connect.client.records.SpeedRecord.Sample> getSamples();
     method public java.time.Instant getStartTime();
     method public java.time.ZoneOffset? getStartZoneOffset();
     property public java.time.Instant endTime;
     property public java.time.ZoneOffset? endZoneOffset;
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public java.util.List<androidx.health.connect.client.records.Speed> samples;
+    property public java.util.List<androidx.health.connect.client.records.SpeedRecord.Sample> samples;
     property public java.time.Instant startTime;
     property public java.time.ZoneOffset? startZoneOffset;
     field public static final androidx.health.connect.client.records.SpeedRecord.Companion Companion;
-    field public static final androidx.health.connect.client.aggregate.AggregateMetric<java.lang.Double> SPEED_AVG;
-    field public static final androidx.health.connect.client.aggregate.AggregateMetric<java.lang.Double> SPEED_MAX;
-    field public static final androidx.health.connect.client.aggregate.AggregateMetric<java.lang.Double> SPEED_MIN;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.Velocity> SPEED_AVG;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.Velocity> SPEED_MAX;
+    field public static final androidx.health.connect.client.aggregate.AggregateMetric<androidx.health.connect.client.units.Velocity> SPEED_MIN;
   }
 
   public static final class SpeedRecord.Companion {
   }
 
+  public static final class SpeedRecord.Sample {
+    ctor public SpeedRecord.Sample(java.time.Instant time, androidx.health.connect.client.units.Velocity speed);
+    method public androidx.health.connect.client.units.Velocity getSpeed();
+    method public java.time.Instant getTime();
+    property public final androidx.health.connect.client.units.Velocity speed;
+    property public final java.time.Instant time;
+  }
+
   public final class StepsCadence {
     ctor public StepsCadence(java.time.Instant time, @FloatRange(from=0.0, to=10000.0) double rate);
     method public double getRate();
@@ -1516,6 +1516,16 @@
   public final class MassKt {
   }
 
+  public final class Percentage implements java.lang.Comparable<androidx.health.connect.client.units.Percentage> {
+    ctor public Percentage(double value);
+    method public int compareTo(androidx.health.connect.client.units.Percentage other);
+    method public double getValue();
+    property public final double value;
+  }
+
+  public final class PercentageKt {
+  }
+
   public final class Power implements java.lang.Comparable<androidx.health.connect.client.units.Power> {
     method public int compareTo(androidx.health.connect.client.units.Power other);
     method public double getKilocaloriesPerDay();
@@ -1569,6 +1579,29 @@
   public final class TemperatureKt {
   }
 
+  public final class Velocity implements java.lang.Comparable<androidx.health.connect.client.units.Velocity> {
+    method public int compareTo(androidx.health.connect.client.units.Velocity other);
+    method public double getKilometersPerHour();
+    method public double getMetersPerSecond();
+    method public double getMilesPerHour();
+    method public static androidx.health.connect.client.units.Velocity kilometersPerHour(double value);
+    method public static androidx.health.connect.client.units.Velocity metersPerSecond(double value);
+    method public static androidx.health.connect.client.units.Velocity milesPerHour(double value);
+    property public final double inKilometersPerHour;
+    property public final double inMetersPerSecond;
+    property public final double inMilesPerHour;
+    field public static final androidx.health.connect.client.units.Velocity.Companion Companion;
+  }
+
+  public static final class Velocity.Companion {
+    method public androidx.health.connect.client.units.Velocity kilometersPerHour(double value);
+    method public androidx.health.connect.client.units.Velocity metersPerSecond(double value);
+    method public androidx.health.connect.client.units.Velocity milesPerHour(double value);
+  }
+
+  public final class VelocityKt {
+  }
+
   public final class Volume implements java.lang.Comparable<androidx.health.connect.client.units.Volume> {
     method public int compareTo(androidx.health.connect.client.units.Volume other);
     method public double getLiters();
diff --git a/health/health-connect-client/build.gradle b/health/health-connect-client/build.gradle
index ae8ba2f..73eb976 100644
--- a/health/health-connect-client/build.gradle
+++ b/health/health-connect-client/build.gradle
@@ -14,22 +14,31 @@
  * limitations under the License.
  */
 
+import androidx.build.BundleInsideHelper
 import androidx.build.LibraryType
 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
-    id("com.google.protobuf")
     id("org.jetbrains.kotlin.android")
 }
 
+BundleInsideHelper.forInsideAar(
+        project,
+        /* from = */ "com.google.protobuf",
+        /* to =   */ "androidx.health.platform.client.proto"
+)
+
 dependencies {
     api(libs.kotlinStdlib)
     // Add dependencies here
     api("androidx.activity:activity:1.2.0")
     api("androidx.annotation:annotation:1.2.0")
-    implementation(libs.protobufLite)
+    bundleInside(project(
+            path: ":health:health-connect-client-proto",
+            configuration: "export"
+    ))
     implementation(libs.guavaListenableFuture)
     implementation(libs.guavaAndroid)
     implementation(libs.kotlinCoroutinesAndroid)
@@ -60,25 +69,6 @@
     namespace "androidx.health.connect.client"
 }
 
-protobuf {
-    protoc {
-        artifact = libs.protobufCompiler.get()
-    }
-
-    // Generates the java proto-lite code for the protos in this project. See
-    // https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
-    // for more information.
-    generateProtoTasks {
-        all().each { task ->
-                task.builtins {
-                    java {
-                        option 'lite'
-                    }
-                }
-        }
-    }
-}
-
 androidx {
     name = "AndroidX Health Connect Client Library"
     type = LibraryType.PUBLISHED_LIBRARY
diff --git a/health/health-connect-client/lint-baseline.xml b/health/health-connect-client/lint-baseline.xml
index a2fac5e..ab2b0f0 100644
--- a/health/health-connect-client/lint-baseline.xml
+++ b/health/health-connect-client/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="BanSynchronizedMethods"
@@ -11,285 +11,6 @@
     </issue>
 
     <issue
-        id="SyntheticAccessor"
-        message="Access to `private` field `mCurrentVersion` of class `Client` requires synthetic accessor"
-        errorLine1="                        mCurrentVersion ="
-        errorLine2="                        ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="SyntheticAccessor"
-        message="Access to `private` field `mConnectionConfiguration` of class `Client` requires synthetic accessor"
-        errorLine1="                        return mConnectionConfiguration;"
-        errorLine2="                               ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="SyntheticAccessor"
-        message="Access to `private` field `mConnectionManager` of class `Client` requires synthetic accessor"
-        errorLine1="                            mConnectionManager.scheduleForExecution("
-        errorLine2="                            ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="SyntheticAccessor"
-        message="Access to `private` field `mConnectionConfiguration` of class `Client` requires synthetic accessor"
-        errorLine1="                                    new BaseQueueOperation(mConnectionConfiguration));"
-        errorLine2="                                                           ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="SyntheticAccessor"
-        message="Access to `private` field `mConnectionManager` of class `Client` requires synthetic accessor"
-        errorLine1="                            mConnectionManager.scheduleForExecution("
-        errorLine2="                            ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="SyntheticAccessor"
-        message="Access to `private` method `createQueueOperation` of class `Client` requires synthetic accessor"
-        errorLine1="                                    createQueueOperation(operation, settableFuture));"
-        errorLine2="                                    ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="SyntheticAccessor"
-        message="Access to `private` method `getService` of class `Client` requires synthetic accessor"
-        errorLine1="                operation.execute(getService(binder), settableFuture);"
-        errorLine2="                                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="LambdaLast"
-        message="Functional interface parameters (such as parameter 1, &quot;operation&quot;, in androidx.health.platform.client.impl.ipc.Client.executeWithVersionCheck) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
-        errorLine1="            RemoteFutureOperation&lt;S, R> operation, int minApiVersion) {"
-        errorLine2="                                                   ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ClientConfiguration clientConfiguration,"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ConnectionManager connectionManager,"
-        errorLine2="            ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ServiceGetter&lt;S> serviceGetter,"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            RemoteOperation&lt;S, Integer> remoteVersionGetter) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected &lt;R> ListenableFuture&lt;R> execute(RemoteOperation&lt;S, R> operation) {"
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected &lt;R> ListenableFuture&lt;R> execute(RemoteOperation&lt;S, R> operation) {"
-        errorLine2="                                              ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected &lt;R> ListenableFuture&lt;R> execute(RemoteFutureOperation&lt;S, R> operation) {"
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected &lt;R> ListenableFuture&lt;R> execute(RemoteFutureOperation&lt;S, R> operation) {"
-        errorLine2="                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected &lt;R> ListenableFuture&lt;R> executeWithVersionCheck("
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            RemoteFutureOperation&lt;S, R> operation, int minApiVersion) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected ListenableFuture&lt;Integer> getCurrentRemoteVersion(boolean forceRefresh) {"
-        errorLine2="              ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected &lt;R> ListenableFuture&lt;R> registerListener("
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ListenerKey listenerKey, RemoteOperation&lt;S, R> registerListenerOperation) {"
-        errorLine2="            ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ListenerKey listenerKey, RemoteOperation&lt;S, R> registerListenerOperation) {"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected &lt;R> ListenableFuture&lt;R> registerListener("
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ListenerKey listenerKey, RemoteFutureOperation&lt;S, R> registerListenerOperation) {"
-        errorLine2="            ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ListenerKey listenerKey, RemoteFutureOperation&lt;S, R> registerListenerOperation) {"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected &lt;R> ListenableFuture&lt;R> unregisterListener("
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ListenerKey listenerKey, RemoteOperation&lt;S, R> unregisterListenerOperation) {"
-        errorLine2="            ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ListenerKey listenerKey, RemoteOperation&lt;S, R> unregisterListenerOperation) {"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected &lt;R> ListenableFuture&lt;R> unregisterListener("
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ListenerKey listenerKey, RemoteFutureOperation&lt;S, R> unregisterListenerOperation) {"
-        errorLine2="            ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ListenerKey listenerKey, RemoteFutureOperation&lt;S, R> unregisterListenerOperation) {"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/platform/client/impl/ipc/Client.java"/>
-    </issue>
-
-    <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    public ClientConfiguration(String apiClientName, String servicePackageName, String bindAction) {"
diff --git a/health/health-connect-client/proguard-rules.pro b/health/health-connect-client/proguard-rules.pro
new file mode 100644
index 0000000..445f2b5
--- /dev/null
+++ b/health/health-connect-client/proguard-rules.pro
@@ -0,0 +1,20 @@
+#  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.
+
+# libproto uses reflection to deserialize a Proto, which Proguard can't accurately detect.
+# Keep all the class members of any generated messages to ensure we can deserialize properly inside
+# these classes.
+-keepclassmembers class * extends androidx.health.platform.client.proto.GeneratedMessageLite {
+  <fields>;
+}
\ No newline at end of file
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ProtoToRecordConverters.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ProtoToRecordConverters.kt
index bf6ae6c..f767c8b 100644
--- a/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ProtoToRecordConverters.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/ProtoToRecordConverters.kt
@@ -63,7 +63,6 @@
 import androidx.health.connect.client.records.SexualActivityRecord
 import androidx.health.connect.client.records.SleepSessionRecord
 import androidx.health.connect.client.records.SleepStageRecord
-import androidx.health.connect.client.records.Speed
 import androidx.health.connect.client.records.SpeedRecord
 import androidx.health.connect.client.records.StepsCadence
 import androidx.health.connect.client.records.StepsCadenceRecord
@@ -81,7 +80,9 @@
 import androidx.health.connect.client.units.kilograms
 import androidx.health.connect.client.units.liters
 import androidx.health.connect.client.units.meters
+import androidx.health.connect.client.units.metersPerSecond
 import androidx.health.connect.client.units.millimetersOfMercury
+import androidx.health.connect.client.units.percent
 import androidx.health.connect.client.units.watts
 import androidx.health.platform.client.proto.DataProto
 import java.time.Instant
@@ -127,7 +128,7 @@
                 )
             "BodyFat" ->
                 BodyFatRecord(
-                    percentage = getDouble("percentage").toInt(),
+                    percentage = getDouble("percentage").percent,
                     time = time,
                     zoneOffset = zoneOffset,
                     metadata = metadata
@@ -292,7 +293,7 @@
                 )
             "OxygenSaturation" ->
                 OxygenSaturationRecord(
-                    percentage = getDouble("percentage").toInt(),
+                    percentage = getDouble("percentage").percent,
                     time = time,
                     zoneOffset = zoneOffset,
                     metadata = metadata
@@ -341,9 +342,9 @@
                     endZoneOffset = endZoneOffset,
                     samples =
                         seriesValuesList.map { value ->
-                            Speed(
+                            SpeedRecord.Sample(
                                 time = Instant.ofEpochMilli(value.instantTimeMillis),
-                                metersPerSecond = value.getDouble("speed"),
+                                speed = value.getDouble("speed").metersPerSecond,
                             )
                         },
                     metadata = metadata,
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/RecordToProtoConverters.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/RecordToProtoConverters.kt
index fbe8142..30199e8 100644
--- a/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/RecordToProtoConverters.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/records/RecordToProtoConverters.kt
@@ -112,7 +112,7 @@
         is BodyFatRecord ->
             instantaneousProto()
                 .setDataType(protoDataType("BodyFat"))
-                .apply { putValues("percentage", doubleVal(percentage.toDouble())) }
+                .apply { putValues("percentage", doubleVal(percentage.value)) }
                 .build()
         is BodyTemperatureRecord ->
             instantaneousProto()
@@ -227,7 +227,7 @@
         is OxygenSaturationRecord ->
             instantaneousProto()
                 .setDataType(protoDataType("OxygenSaturation"))
-                .apply { putValues("percentage", doubleVal(percentage.toDouble())) }
+                .apply { putValues("percentage", doubleVal(percentage.value)) }
                 .build()
         is PowerRecord ->
             toProto(dataTypeName = "PowerSeries") { sample ->
@@ -254,7 +254,7 @@
         is SpeedRecord ->
             toProto(dataTypeName = "SpeedSeries") { sample ->
                 DataProto.SeriesValue.newBuilder()
-                    .putValues("speed", doubleVal(sample.metersPerSecond))
+                    .putValues("speed", doubleVal(sample.speed.inMetersPerSecond))
                     .setInstantTimeMillis(sample.time.toEpochMilli())
                     .build()
             }
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyFatRecord.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyFatRecord.kt
index 458fa52..7f51c1b 100644
--- a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyFatRecord.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyFatRecord.kt
@@ -16,6 +16,7 @@
 package androidx.health.connect.client.records
 
 import androidx.health.connect.client.records.metadata.Metadata
+import androidx.health.connect.client.units.Percentage
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -25,16 +26,19 @@
  */
 public class BodyFatRecord(
     /** Percentage. Required field. Valid range: 0-100. */
-    public val percentage: Int,
+    public val percentage: Percentage,
     override val time: Instant,
     override val zoneOffset: ZoneOffset?,
     override val metadata: Metadata = Metadata.EMPTY,
 ) : InstantaneousRecord {
 
     init {
-        requireNonNegative(value = percentage, name = "percentage")
+        requireNonNegative(value = percentage.value, name = "percentage")
     }
 
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (other !is BodyFatRecord) return false
@@ -47,9 +51,11 @@
         return true
     }
 
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
     override fun hashCode(): Int {
-        var result = 0
-        result = 31 * result + percentage.hashCode()
+        var result = percentage.hashCode()
         result = 31 * result + time.hashCode()
         result = 31 * result + (zoneOffset?.hashCode() ?: 0)
         result = 31 * result + metadata.hashCode()
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/OxygenSaturationRecord.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/OxygenSaturationRecord.kt
index 3f4b3f8..4c9c0f6 100644
--- a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/OxygenSaturationRecord.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/OxygenSaturationRecord.kt
@@ -16,6 +16,7 @@
 package androidx.health.connect.client.records
 
 import androidx.health.connect.client.records.metadata.Metadata
+import androidx.health.connect.client.units.Percentage
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -26,16 +27,19 @@
  */
 public class OxygenSaturationRecord(
     /** Percentage. Required field. Valid range: 0-100. */
-    public val percentage: Int,
+    public val percentage: Percentage,
     override val time: Instant,
     override val zoneOffset: ZoneOffset?,
     override val metadata: Metadata = Metadata.EMPTY,
 ) : InstantaneousRecord {
 
     init {
-        requireNonNegative(value = percentage, name = "percentage")
+        requireNonNegative(value = percentage.value, name = "percentage")
     }
 
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (other !is OxygenSaturationRecord) return false
@@ -48,9 +52,11 @@
         return true
     }
 
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
     override fun hashCode(): Int {
-        var result = 0
-        result = 31 * result + percentage.hashCode()
+        var result = percentage.hashCode()
         result = 31 * result + time.hashCode()
         result = 31 * result + (zoneOffset?.hashCode() ?: 0)
         result = 31 * result + metadata.hashCode()
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SpeedRecord.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SpeedRecord.kt
index 4725ab0a..e14bc6f 100644
--- a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SpeedRecord.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/SpeedRecord.kt
@@ -15,9 +15,9 @@
  */
 package androidx.health.connect.client.records
 
-import androidx.annotation.FloatRange
 import androidx.health.connect.client.aggregate.AggregateMetric
 import androidx.health.connect.client.records.metadata.Metadata
+import androidx.health.connect.client.units.Velocity
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -30,9 +30,9 @@
     override val startZoneOffset: ZoneOffset?,
     override val endTime: Instant,
     override val endZoneOffset: ZoneOffset?,
-    override val samples: List<Speed>,
+    override val samples: List<Sample>,
     override val metadata: Metadata = Metadata.EMPTY,
-) : SeriesRecord<Speed> {
+) : SeriesRecord<SpeedRecord.Sample> {
 
     /*
      * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
@@ -73,11 +73,12 @@
          * [androidx.health.connect.client.aggregate.AggregationResult].
          */
         @JvmField
-        val SPEED_AVG: AggregateMetric<Double> =
+        val SPEED_AVG: AggregateMetric<Velocity> =
             AggregateMetric.doubleMetric(
-                SPEED_TYPE_NAME,
-                AggregateMetric.AggregationType.AVERAGE,
-                SPEED_FIELD_NAME
+                dataTypeName = SPEED_TYPE_NAME,
+                aggregationType = AggregateMetric.AggregationType.AVERAGE,
+                fieldName = SPEED_FIELD_NAME,
+                mapper = Velocity::metersPerSecond,
             )
 
         /**
@@ -85,11 +86,12 @@
          * [androidx.health.connect.client.aggregate.AggregationResult].
          */
         @JvmField
-        val SPEED_MIN: AggregateMetric<Double> =
+        val SPEED_MIN: AggregateMetric<Velocity> =
             AggregateMetric.doubleMetric(
-                SPEED_TYPE_NAME,
-                AggregateMetric.AggregationType.MINIMUM,
-                SPEED_FIELD_NAME
+                dataTypeName = SPEED_TYPE_NAME,
+                aggregationType = AggregateMetric.AggregationType.MINIMUM,
+                fieldName = SPEED_FIELD_NAME,
+                mapper = Velocity::metersPerSecond,
             )
 
         /**
@@ -97,51 +99,46 @@
          * [androidx.health.connect.client.aggregate.AggregationResult].
          */
         @JvmField
-        val SPEED_MAX: AggregateMetric<Double> =
+        val SPEED_MAX: AggregateMetric<Velocity> =
             AggregateMetric.doubleMetric(
-                SPEED_TYPE_NAME,
-                AggregateMetric.AggregationType.MAXIMUM,
-                SPEED_FIELD_NAME
+                dataTypeName = SPEED_TYPE_NAME,
+                aggregationType = AggregateMetric.AggregationType.MAXIMUM,
+                fieldName = SPEED_FIELD_NAME,
+                mapper = Velocity::metersPerSecond,
             )
     }
-}
 
-/**
- * Represents a single measurement of the speed, a scalar magnitude.
- *
- * @param time The point in time when the measurement was taken.
- * @param metersPerSecond Speed in meters per second. Valid range: 0-1000000.
- *
- * @see SpeedRecord
- */
-public class Speed(
-    val time: Instant,
-    @FloatRange(from = 0.0, to = 1_000_000.0) val metersPerSecond: Double,
-) {
-
-    init {
-        requireNonNegative(value = metersPerSecond, name = "metersPerSecond")
-    }
-
-    /*
-     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+    /**
+     * Represents a single measurement of the speed, a scalar magnitude.
+     *
+     * @param time The point in time when the measurement was taken.
+     * @param speed Speed in [Velocity] unit. Valid range: 0-1000000 meters/sec.
+     *
+     * @see SpeedRecord
      */
-    override fun equals(other: Any?): Boolean {
-        if (this === other) return true
-        if (other !is Speed) return false
+    public class Sample(
+        val time: Instant,
+        val speed: Velocity,
+    ) {
 
-        if (time != other.time) return false
-        if (metersPerSecond != other.metersPerSecond) return false
+        init {
+            speed.requireNotLess(other = speed.zero(), name = "speed")
+        }
 
-        return true
-    }
+        override fun equals(other: Any?): Boolean {
+            if (this === other) return true
+            if (other !is Sample) return false
 
-    /*
-     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
-     */
-    override fun hashCode(): Int {
-        var result = time.hashCode()
-        result = 31 * result + metersPerSecond.hashCode()
-        return result
+            if (time != other.time) return false
+            if (speed != other.speed) return false
+
+            return true
+        }
+
+        override fun hashCode(): Int {
+            var result = time.hashCode()
+            result = 31 * result + speed.hashCode()
+            return result
+        }
     }
 }
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/units/Percentage.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/units/Percentage.kt
new file mode 100644
index 0000000..c7a13d1
--- /dev/null
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/units/Percentage.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.health.connect.client.units
+
+/** Represents a value as a percentage, not a fraction - for example 100%, 89.62%, etc. */
+class Percentage(val value: Double) : Comparable<Percentage> {
+
+    override fun compareTo(other: Percentage): Int = value.compareTo(other.value)
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Percentage) return false
+
+        if (value != other.value) return false
+
+        return true
+    }
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun hashCode(): Int {
+        return value.hashCode()
+    }
+
+    override fun toString(): String = "$value%"
+}
+
+/** Creates [Percentage] with the specified percentage value, not a fraction. */
+@get:JvmSynthetic
+val Double.percent: Percentage
+    get() = Percentage(value = this)
+
+/** Creates [Percentage] with the specified percentage value, not a fraction. */
+@get:JvmSynthetic
+val Long.percent: Percentage
+    get() = toDouble().percent
+
+/** Creates [Percentage] with the specified percentage value, not a fraction. */
+@get:JvmSynthetic
+val Float.percent: Percentage
+    get() = toDouble().percent
+
+/** Creates [Percentage] with the specified percentage value, not a fraction. */
+@get:JvmSynthetic
+val Int.percent: Percentage
+    get() = toDouble().percent
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/units/Velocity.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/units/Velocity.kt
new file mode 100644
index 0000000..9a15e36
--- /dev/null
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/units/Velocity.kt
@@ -0,0 +1,176 @@
+/*
+ * 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.health.connect.client.units
+
+/**
+ * Represents a unit of speed. Supported units:
+ *
+ * - metersPerSecond - see [Velocity.metersPerSecond], [Double.metersPerSecond]
+ * - kilometersPerHour - see [Velocity.kilometersPerHour], [Double.kilometersPerHour]
+ * - milesPerHour - see [Velocity.milesPerHour], [Double.milesPerHour]
+ */
+class Velocity private constructor(
+    private val value: Double,
+    private val type: Type,
+) : Comparable<Velocity> {
+
+    /** Returns the velocity in meters per second. */
+    @get:JvmName("getMetersPerSecond")
+    val inMetersPerSecond: Double
+        get() = value * type.metersPerSecondPerUnit
+
+    /** Returns the velocity in kilometers per hour. */
+    @get:JvmName("getKilometersPerHour")
+    val inKilometersPerHour: Double
+        get() = get(type = Type.KILOMETERS_PER_HOUR)
+
+    /** Returns the velocity in miles per hour. */
+    @get:JvmName("getMilesPerHour")
+    val inMilesPerHour: Double
+        get() = get(type = Type.MILES_PER_HOUR)
+
+    private fun get(type: Type): Double =
+        if (this.type == type) value else inMetersPerSecond / type.metersPerSecondPerUnit
+
+    /** Returns zero [Velocity] of the same [Type]. */
+    internal fun zero(): Velocity = ZEROS.getValue(type)
+
+    override fun compareTo(other: Velocity): Int =
+        if (type == other.type) {
+            value.compareTo(other.value)
+        } else {
+            inMetersPerSecond.compareTo(other.inMetersPerSecond)
+        }
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Velocity) return false
+
+        if (value != other.value) return false
+        if (type != other.type) return false
+
+        return true
+    }
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun hashCode(): Int {
+        var result = value.hashCode()
+        result = 31 * result + type.hashCode()
+        return result
+    }
+
+    override fun toString(): String = "$value ${type.title}"
+
+    companion object {
+        private val ZEROS = Type.values().associateWith { Velocity(value = 0.0, type = it) }
+
+        /** Creates [Velocity] with the specified value in meters per second. */
+        @JvmStatic
+        fun metersPerSecond(value: Double): Velocity = Velocity(value, Type.METERS_PER_SECOND)
+
+        /** Creates [Velocity] with the specified value in kilometers per hour. */
+        @JvmStatic
+        fun kilometersPerHour(value: Double): Velocity = Velocity(value, Type.KILOMETERS_PER_HOUR)
+
+        /** Creates [Velocity] with the specified value in miles per hour. */
+        @JvmStatic
+        fun milesPerHour(value: Double): Velocity = Velocity(value, Type.MILES_PER_HOUR)
+    }
+
+    private enum class Type {
+        METERS_PER_SECOND {
+            override val metersPerSecondPerUnit: Double = 1.0
+            override val title: String = "meters/sec"
+        },
+        KILOMETERS_PER_HOUR {
+            override val metersPerSecondPerUnit: Double = 1.0 / 3.6
+            override val title: String = "km/h"
+        },
+        MILES_PER_HOUR {
+            override val metersPerSecondPerUnit: Double = 0.447040357632
+            override val title: String = "miles/h"
+        };
+
+        abstract val metersPerSecondPerUnit: Double
+        abstract val title: String
+    }
+}
+
+/** Creates [Velocity] with the specified value in meters per second. */
+@get:JvmSynthetic
+val Double.metersPerSecond: Velocity
+    get() = Velocity.metersPerSecond(value = this)
+
+/** Creates [Velocity] with the specified value in meters per second. */
+@get:JvmSynthetic
+val Long.metersPerSecond: Velocity
+    get() = toDouble().metersPerSecond
+
+/** Creates [Velocity] with the specified value in meters per second. */
+@get:JvmSynthetic
+val Float.metersPerSecond: Velocity
+    get() = toDouble().metersPerSecond
+
+/** Creates [Velocity] with the specified value in meters per second. */
+@get:JvmSynthetic
+val Int.metersPerSecond: Velocity
+    get() = toDouble().metersPerSecond
+
+/** Creates [Velocity] with the specified value in kilometers per hour. */
+@get:JvmSynthetic
+val Double.kilometersPerHour: Velocity
+    get() = Velocity.kilometersPerHour(value = this)
+
+/** Creates [Velocity] with the specified value in kilometers per hour. */
+@get:JvmSynthetic
+val Long.kilometersPerHour: Velocity
+    get() = toDouble().kilometersPerHour
+
+/** Creates [Velocity] with the specified value in kilometers per hour. */
+@get:JvmSynthetic
+val Float.kilometersPerHour: Velocity
+    get() = toDouble().kilometersPerHour
+
+/** Creates [Velocity] with the specified value in kilometers per hour. */
+@get:JvmSynthetic
+val Int.kilometersPerHour: Velocity
+    get() = toDouble().kilometersPerHour
+
+/** Creates [Velocity] with the specified value in miles per hour. */
+@get:JvmSynthetic
+val Double.milesPerHour: Velocity
+    get() = Velocity.milesPerHour(value = this)
+
+/** Creates [Velocity] with the specified value in miles per hour. */
+@get:JvmSynthetic
+val Long.milesPerHour: Velocity
+    get() = toDouble().milesPerHour
+
+/** Creates [Velocity] with the specified value in miles per hour. */
+@get:JvmSynthetic
+val Float.milesPerHour: Velocity
+    get() = toDouble().milesPerHour
+
+/** Creates [Velocity] with the specified value in miles per hour. */
+@get:JvmSynthetic
+val Int.milesPerHour: Velocity
+    get() = toDouble().milesPerHour
diff --git a/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoData.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoData.kt
index ade72dd..62a1c57 100644
--- a/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoData.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoData.kt
@@ -16,7 +16,7 @@
 package androidx.health.platform.client.impl.data
 
 import androidx.annotation.RestrictTo
-import com.google.protobuf.MessageLite
+import androidx.health.platform.client.proto.MessageLite
 
 /** Base class for data objects backed by protos. */
 @RestrictTo(RestrictTo.Scope.LIBRARY)
diff --git a/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoParcelable.kt b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoParcelable.kt
index 0c70c81..1a74b65 100644
--- a/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoParcelable.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/platform/client/impl/data/ProtoParcelable.kt
@@ -21,7 +21,7 @@
 import android.os.Parcelable.Creator
 import android.os.SharedMemory
 import androidx.annotation.RestrictTo
-import com.google.protobuf.MessageLite
+import androidx.health.platform.client.proto.MessageLite
 
 /**
  * Base class for parcelables backed by protos.
diff --git a/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/records/AllRecordsConverterTest.kt b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/records/AllRecordsConverterTest.kt
index ea11ca7..2679086d 100644
--- a/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/records/AllRecordsConverterTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/connect/client/impl/converters/records/AllRecordsConverterTest.kt
@@ -69,7 +69,6 @@
 import androidx.health.connect.client.records.SleepSessionRecord
 import androidx.health.connect.client.records.SleepStageRecord
 import androidx.health.connect.client.records.SleepStageRecord.StageType
-import androidx.health.connect.client.records.Speed
 import androidx.health.connect.client.records.SpeedRecord
 import androidx.health.connect.client.records.StepsCadence
 import androidx.health.connect.client.records.StepsCadenceRecord
@@ -91,7 +90,9 @@
 import androidx.health.connect.client.units.kilograms
 import androidx.health.connect.client.units.liters
 import androidx.health.connect.client.units.meters
+import androidx.health.connect.client.units.metersPerSecond
 import androidx.health.connect.client.units.millimetersOfMercury
+import androidx.health.connect.client.units.percent
 import androidx.health.connect.client.units.watts
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
@@ -198,7 +199,7 @@
     fun testBodyFat() {
         val data =
             BodyFatRecord(
-                percentage = 1,
+                percentage = 1.percent,
                 time = START_TIME,
                 zoneOffset = END_ZONE_OFFSET,
                 metadata = TEST_METADATA
@@ -522,7 +523,7 @@
     fun testOxygenSaturation() {
         val data =
             OxygenSaturationRecord(
-                percentage = 1,
+                percentage = 1.percent,
                 time = START_TIME,
                 zoneOffset = END_ZONE_OFFSET,
                 metadata = TEST_METADATA
@@ -610,13 +611,13 @@
                 endZoneOffset = END_ZONE_OFFSET,
                 samples =
                     listOf(
-                        Speed(
+                        SpeedRecord.Sample(
                             time = START_TIME,
-                            metersPerSecond = 1.0,
+                            speed = 1.metersPerSecond,
                         ),
-                        Speed(
+                        SpeedRecord.Sample(
                             time = START_TIME,
-                            metersPerSecond = 2.0,
+                            speed = 2.metersPerSecond,
                         ),
                     ),
                 metadata = TEST_METADATA,
diff --git a/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/data/ProtoParcelableTest.kt b/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/data/ProtoParcelableTest.kt
index 7388283..b295712 100644
--- a/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/data/ProtoParcelableTest.kt
+++ b/health/health-connect-client/src/test/java/androidx/health/platform/client/impl/data/ProtoParcelableTest.kt
@@ -17,10 +17,10 @@
 
 import android.os.Parcel
 import android.os.Parcelable
+import androidx.health.platform.client.proto.ByteString
+import androidx.health.platform.client.proto.BytesValue
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
-import com.google.protobuf.ByteString
-import com.google.protobuf.BytesValue
 import org.junit.Test
 import org.junit.runner.RunWith
 
diff --git a/health/health-services-client/lint-baseline.xml b/health/health-services-client/lint-baseline.xml
index 4e47030..bc9039d 100644
--- a/health/health-services-client/lint-baseline.xml
+++ b/health/health-services-client/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="BanKeepAnnotation"
@@ -20,15 +20,6 @@
     </issue>
 
     <issue
-        id="BanKeepAnnotation"
-        message="Uses @Keep annotation"
-        errorLine1="    @Keep"
-        errorLine2="    ~~~~~">
-        <location
-            file="src/main/java/androidx/health/services/client/data/DataPoints.kt"/>
-    </issue>
-
-    <issue
         id="BanParcelableUsage"
         message="Class implements android.os.Parcelable"
         errorLine1="public data class ExerciseGoalRequest(val packageName: String, val exerciseGoal: ExerciseGoal) :"
@@ -76,24 +67,6 @@
     <issue
         id="BanSynchronizedMethods"
         message="Use of synchronized methods is not recommended"
-        errorLine1="        @Synchronized"
-        errorLine2="        ^">
-        <location
-            file="src/main/java/androidx/health/services/client/impl/PassiveMonitoringCallbackStub.kt"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="        @Synchronized"
-        errorLine2="        ^">
-        <location
-            file="src/main/java/androidx/health/services/client/impl/PassiveMonitoringCallbackStub.kt"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
         errorLine1="    private synchronized void handleRetriableDisconnection(Throwable throwable) {"
         errorLine2="    ^">
         <location
@@ -101,15 +74,6 @@
     </issue>
 
     <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        get() = ServiceBackedMeasureClient.getClient(applicationContext)"
-        errorLine2="                                           ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/services/client/impl/ServiceBackedHealthServicesClient.kt"/>
-    </issue>
-
-    <issue
         id="SyntheticAccessor"
         message="Access to `private` field `mCurrentVersion` of class `Client` requires synthetic accessor"
         errorLine1="                        mCurrentVersion ="
@@ -174,15 +138,6 @@
 
     <issue
         id="SyntheticAccessor"
-        message="Access to `private` method `initialize` of class `Companion` requires synthetic accessor"
-        errorLine1="        private val IDS = initialize()"
-        errorLine2="                          ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/services/client/data/ExerciseType.kt"/>
-    </issue>
-
-    <issue
-        id="SyntheticAccessor"
         message="Access to `private` constructor of class `ExerciseUpdateListenerStub` requires synthetic accessor"
         errorLine1="            return listeners.getOrPut(listener) { ExerciseUpdateListenerStub(listener, executor) }"
         errorLine2="                                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -200,15 +155,6 @@
     </issue>
 
     <issue
-        id="SyntheticAccessor"
-        message="Access to `private` constructor of class `PassiveMonitoringCallbackStub` requires synthetic accessor"
-        errorLine1="                PassiveMonitoringCallbackStub(packageName, callback)"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/services/client/impl/PassiveMonitoringCallbackStub.kt"/>
-    </issue>
-
-    <issue
         id="LambdaLast"
         message="Functional interface parameters (such as parameter 1, &quot;operation&quot;, in androidx.health.services.client.impl.ipc.Client.executeWithVersionCheck) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
         errorLine1="            RemoteFutureOperation&lt;S, R> operation, int minApiVersion) {"
@@ -775,22 +721,4 @@
             file="src/main/java/androidx/health/services/client/impl/ipc/internal/ServiceConnection.java"/>
     </issue>
 
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void execute(IBinder binder, SettableFuture&lt;R> resultFuture) throws RemoteException;"
-        errorLine2="                 ~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/services/client/impl/ipc/ServiceOperation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void execute(IBinder binder, SettableFuture&lt;R> resultFuture) throws RemoteException;"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/health/services/client/impl/ipc/ServiceOperation.java"/>
-    </issue>
-
 </issues>
diff --git a/heifwriter/heifwriter/lint-baseline.xml b/heifwriter/heifwriter/lint-baseline.xml
index 383be1f..90fe3a3 100644
--- a/heifwriter/heifwriter/lint-baseline.xml
+++ b/heifwriter/heifwriter/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="BanSynchronizedMethods"
diff --git a/leanback/leanback-preference/lint-baseline.xml b/leanback/leanback-preference/lint-baseline.xml
index 352aa9c..549e0a5 100644
--- a/leanback/leanback-preference/lint-baseline.xml
+++ b/leanback/leanback-preference/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="MissingLeanbackLauncher"
diff --git a/leanback/leanback/api/current.txt b/leanback/leanback/api/current.txt
index fb9da3f..6cf18f9 100644
--- a/leanback/leanback/api/current.txt
+++ b/leanback/leanback/api/current.txt
@@ -509,10 +509,10 @@
     method public void notifyActionChanged(int);
     method public void notifyButtonActionChanged(int);
     method protected void onAddSharedElementTransition(androidx.fragment.app.FragmentTransaction, androidx.leanback.app.GuidedStepSupportFragment);
-    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
     method public android.view.View? onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
-    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
     method public androidx.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
     method public androidx.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
@@ -952,13 +952,13 @@
 
   public class VerticalGridSupportFragment extends androidx.leanback.app.BaseSupportFragment {
     ctor public VerticalGridSupportFragment();
-    method public androidx.leanback.widget.ObjectAdapter! getAdapter();
-    method public androidx.leanback.widget.VerticalGridPresenter! getGridPresenter();
-    method public androidx.leanback.widget.OnItemViewClickedListener! getOnItemViewClickedListener();
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter!);
-    method public void setGridPresenter(androidx.leanback.widget.VerticalGridPresenter!);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener!);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener!);
+    method public androidx.leanback.widget.ObjectAdapter? getAdapter();
+    method public androidx.leanback.widget.VerticalGridPresenter? getGridPresenter();
+    method public androidx.leanback.widget.OnItemViewClickedListener? getOnItemViewClickedListener();
+    method public void setAdapter(androidx.leanback.widget.ObjectAdapter?);
+    method public void setGridPresenter(androidx.leanback.widget.VerticalGridPresenter);
+    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener?);
+    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener?);
     method public void setSelectedPosition(int);
   }
 
@@ -1047,26 +1047,26 @@
 
   public class CompositeDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public CompositeDrawable();
-    method public void addChildDrawable(android.graphics.drawable.Drawable!);
-    method public void draw(android.graphics.Canvas!);
-    method public androidx.leanback.graphics.CompositeDrawable.ChildDrawable! getChildAt(int);
+    method public void addChildDrawable(android.graphics.drawable.Drawable);
+    method public void draw(android.graphics.Canvas);
+    method public androidx.leanback.graphics.CompositeDrawable.ChildDrawable getChildAt(int);
     method public int getChildCount();
-    method public android.graphics.drawable.Drawable! getDrawable(int);
+    method public android.graphics.drawable.Drawable getDrawable(int);
     method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable!);
+    method public void invalidateDrawable(android.graphics.drawable.Drawable);
     method public void removeChild(int);
-    method public void removeDrawable(android.graphics.drawable.Drawable!);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable!, Runnable!, long);
+    method public void removeDrawable(android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long);
     method public void setAlpha(int);
-    method public void setChildDrawableAt(int, android.graphics.drawable.Drawable!);
-    method public void setColorFilter(android.graphics.ColorFilter!);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable!, Runnable!);
+    method public void setChildDrawableAt(int, android.graphics.drawable.Drawable);
+    method public void setColorFilter(android.graphics.ColorFilter?);
+    method public void unscheduleDrawable(android.graphics.drawable.Drawable, Runnable);
   }
 
   public static final class CompositeDrawable.ChildDrawable {
-    ctor public CompositeDrawable.ChildDrawable(android.graphics.drawable.Drawable!, androidx.leanback.graphics.CompositeDrawable!);
-    method public androidx.leanback.graphics.BoundsRule! getBoundsRule();
-    method public android.graphics.drawable.Drawable! getDrawable();
+    ctor public CompositeDrawable.ChildDrawable(android.graphics.drawable.Drawable, androidx.leanback.graphics.CompositeDrawable);
+    method public androidx.leanback.graphics.BoundsRule getBoundsRule();
+    method public android.graphics.drawable.Drawable getDrawable();
     method public void recomputeBounds();
     field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable!,java.lang.Integer!>! BOTTOM_ABSOLUTE;
     field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable!,java.lang.Float!>! BOTTOM_FRACTION;
@@ -1392,17 +1392,17 @@
 
   public abstract class AbstractDetailsDescriptionPresenter extends androidx.leanback.widget.Presenter {
     ctor public AbstractDetailsDescriptionPresenter();
-    method protected abstract void onBindDescription(androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder!, Object!);
-    method public final void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
-    method public final androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
+    method protected abstract void onBindDescription(androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder, Object);
+    method public final void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object);
+    method public final androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
   }
 
   public static class AbstractDetailsDescriptionPresenter.ViewHolder extends androidx.leanback.widget.Presenter.ViewHolder {
-    ctor public AbstractDetailsDescriptionPresenter.ViewHolder(android.view.View!);
-    method public android.widget.TextView! getBody();
-    method public android.widget.TextView! getSubtitle();
-    method public android.widget.TextView! getTitle();
+    ctor public AbstractDetailsDescriptionPresenter.ViewHolder(android.view.View);
+    method public android.widget.TextView getBody();
+    method public android.widget.TextView getSubtitle();
+    method public android.widget.TextView getTitle();
   }
 
   public abstract class AbstractMediaItemPresenter extends androidx.leanback.widget.RowPresenter {
@@ -1462,20 +1462,20 @@
 
   public class Action {
     ctor public Action(long);
-    ctor public Action(long, CharSequence!);
-    ctor public Action(long, CharSequence!, CharSequence!);
-    ctor public Action(long, CharSequence!, CharSequence!, android.graphics.drawable.Drawable!);
+    ctor public Action(long, CharSequence?);
+    ctor public Action(long, CharSequence?, CharSequence?);
+    ctor public Action(long, CharSequence?, CharSequence?, android.graphics.drawable.Drawable?);
     method public final void addKeyCode(int);
-    method public final android.graphics.drawable.Drawable! getIcon();
+    method public final android.graphics.drawable.Drawable? getIcon();
     method public final long getId();
-    method public final CharSequence! getLabel1();
-    method public final CharSequence! getLabel2();
+    method public final CharSequence? getLabel1();
+    method public final CharSequence? getLabel2();
     method public final void removeKeyCode(int);
     method public final boolean respondsToKeyCode(int);
-    method public final void setIcon(android.graphics.drawable.Drawable!);
+    method public final void setIcon(android.graphics.drawable.Drawable?);
     method public final void setId(long);
-    method public final void setLabel1(CharSequence!);
-    method public final void setLabel2(CharSequence!);
+    method public final void setLabel1(CharSequence?);
+    method public final void setLabel2(CharSequence?);
     field public static final long NO_ID = -1L; // 0xffffffffffffffffL
   }
 
@@ -1597,22 +1597,22 @@
 
   public class DetailsOverviewLogoPresenter extends androidx.leanback.widget.Presenter {
     ctor public DetailsOverviewLogoPresenter();
-    method public boolean isBoundToImage(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder!, androidx.leanback.widget.DetailsOverviewRow!);
-    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
-    method public android.view.View! onCreateView(android.view.ViewGroup!);
-    method public androidx.leanback.widget.Presenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void setContext(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder!, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder!, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter!);
+    method public boolean isBoundToImage(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, androidx.leanback.widget.DetailsOverviewRow?);
+    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object);
+    method public android.view.View onCreateView(android.view.ViewGroup);
+    method public androidx.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
+    method public void setContext(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder?, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter?);
   }
 
   public static class DetailsOverviewLogoPresenter.ViewHolder extends androidx.leanback.widget.Presenter.ViewHolder {
-    ctor public DetailsOverviewLogoPresenter.ViewHolder(android.view.View!);
-    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter! getParentPresenter();
-    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder! getParentViewHolder();
+    ctor public DetailsOverviewLogoPresenter.ViewHolder(android.view.View);
+    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter? getParentPresenter();
+    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder? getParentViewHolder();
     method public boolean isSizeFromDrawableIntrinsic();
     method public void setSizeFromDrawableIntrinsic(boolean);
-    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter! mParentPresenter;
-    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder! mParentViewHolder;
+    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter? mParentPresenter;
+    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder? mParentViewHolder;
   }
 
   public class DetailsOverviewRow extends androidx.leanback.widget.Row {
@@ -1793,16 +1793,16 @@
     ctor protected GuidedAction();
     method public String![]! getAutofillHints();
     method public int getCheckSetId();
-    method public CharSequence! getDescription();
+    method public CharSequence? getDescription();
     method public int getDescriptionEditInputType();
     method public int getDescriptionInputType();
-    method public CharSequence! getEditDescription();
+    method public CharSequence? getEditDescription();
     method public int getEditInputType();
-    method public CharSequence! getEditTitle();
+    method public CharSequence? getEditTitle();
     method public int getInputType();
-    method public android.content.Intent! getIntent();
-    method public java.util.List<androidx.leanback.widget.GuidedAction!>! getSubActions();
-    method public CharSequence! getTitle();
+    method public android.content.Intent? getIntent();
+    method public java.util.List<androidx.leanback.widget.GuidedAction!>? getSubActions();
+    method public CharSequence? getTitle();
     method public boolean hasEditableActivatorView();
     method public boolean hasMultilineDescription();
     method public boolean hasNext();
@@ -1816,17 +1816,17 @@
     method public boolean isEditable();
     method public boolean isEnabled();
     method public boolean isFocusable();
-    method public void onRestoreInstanceState(android.os.Bundle!, String!);
-    method public void onSaveInstanceState(android.os.Bundle!, String!);
+    method public void onRestoreInstanceState(android.os.Bundle, String);
+    method public void onSaveInstanceState(android.os.Bundle, String);
     method public void setChecked(boolean);
-    method public void setDescription(CharSequence!);
-    method public void setEditDescription(CharSequence!);
-    method public void setEditTitle(CharSequence!);
+    method public void setDescription(CharSequence?);
+    method public void setEditDescription(CharSequence?);
+    method public void setEditTitle(CharSequence?);
     method public void setEnabled(boolean);
     method public void setFocusable(boolean);
-    method public void setIntent(android.content.Intent!);
-    method public void setSubActions(java.util.List<androidx.leanback.widget.GuidedAction!>!);
-    method public void setTitle(CharSequence!);
+    method public void setIntent(android.content.Intent?);
+    method public void setSubActions(java.util.List<androidx.leanback.widget.GuidedAction!>?);
+    method public void setTitle(CharSequence?);
     field public static final long ACTION_ID_CANCEL = -5L; // 0xfffffffffffffffbL
     field public static final long ACTION_ID_CONTINUE = -7L; // 0xfffffffffffffff9L
     field public static final long ACTION_ID_CURRENT = -3L; // 0xfffffffffffffffdL
@@ -1842,44 +1842,44 @@
 
   public static class GuidedAction.Builder extends androidx.leanback.widget.GuidedAction.BuilderBase<androidx.leanback.widget.GuidedAction.Builder> {
     ctor @Deprecated public GuidedAction.Builder();
-    ctor public GuidedAction.Builder(android.content.Context!);
-    method public androidx.leanback.widget.GuidedAction! build();
+    ctor public GuidedAction.Builder(android.content.Context?);
+    method public androidx.leanback.widget.GuidedAction build();
   }
 
   public abstract static class GuidedAction.BuilderBase<B extends androidx.leanback.widget.GuidedAction.BuilderBase> {
-    ctor public GuidedAction.BuilderBase(android.content.Context!);
-    method protected final void applyValues(androidx.leanback.widget.GuidedAction!);
+    ctor public GuidedAction.BuilderBase(android.content.Context);
+    method protected final void applyValues(androidx.leanback.widget.GuidedAction);
     method public B! autoSaveRestoreEnabled(boolean);
     method public B! autofillHints(java.lang.String!...);
     method public B! checkSetId(int);
     method public B! checked(boolean);
     method public B! clickAction(long);
-    method public B! description(CharSequence!);
+    method public B! description(CharSequence?);
     method public B! description(@StringRes int);
     method public B! descriptionEditInputType(int);
     method public B! descriptionEditable(boolean);
     method public B! descriptionInputType(int);
-    method public B! editDescription(CharSequence!);
+    method public B! editDescription(CharSequence?);
     method public B! editDescription(@StringRes int);
     method public B! editInputType(int);
-    method public B! editTitle(CharSequence!);
+    method public B! editTitle(CharSequence?);
     method public B! editTitle(@StringRes int);
     method public B! editable(boolean);
     method public B! enabled(boolean);
     method public B! focusable(boolean);
-    method public android.content.Context! getContext();
+    method public android.content.Context getContext();
     method public B! hasEditableActivatorView(boolean);
     method public B! hasNext(boolean);
-    method public B! icon(android.graphics.drawable.Drawable!);
+    method public B! icon(android.graphics.drawable.Drawable?);
     method public B! icon(@DrawableRes int);
     method @Deprecated public B! iconResourceId(@DrawableRes int, android.content.Context!);
     method public B! id(long);
     method public B! infoOnly(boolean);
     method public B! inputType(int);
-    method public B! intent(android.content.Intent!);
+    method public B! intent(android.content.Intent?);
     method public B! multilineDescription(boolean);
-    method public B! subActions(java.util.List<androidx.leanback.widget.GuidedAction!>!);
-    method public B! title(CharSequence!);
+    method public B! subActions(java.util.List<androidx.leanback.widget.GuidedAction!>?);
+    method public B! title(CharSequence?);
     method public B! title(@StringRes int);
   }
 
@@ -2167,19 +2167,19 @@
   public static class ListRowPresenter.SelectItemViewHolderTask extends androidx.leanback.widget.Presenter.ViewHolderTask {
     ctor public ListRowPresenter.SelectItemViewHolderTask(int);
     method public int getItemPosition();
-    method public androidx.leanback.widget.Presenter.ViewHolderTask! getItemTask();
+    method public androidx.leanback.widget.Presenter.ViewHolderTask? getItemTask();
     method public boolean isSmoothScroll();
     method public void setItemPosition(int);
-    method public void setItemTask(androidx.leanback.widget.Presenter.ViewHolderTask!);
+    method public void setItemTask(androidx.leanback.widget.Presenter.ViewHolderTask?);
     method public void setSmoothScroll(boolean);
   }
 
   public static class ListRowPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
-    ctor public ListRowPresenter.ViewHolder(android.view.View!, androidx.leanback.widget.HorizontalGridView!, androidx.leanback.widget.ListRowPresenter!);
-    method public final androidx.leanback.widget.ItemBridgeAdapter! getBridgeAdapter();
-    method public final androidx.leanback.widget.HorizontalGridView! getGridView();
-    method public androidx.leanback.widget.Presenter.ViewHolder! getItemViewHolder(int);
-    method public final androidx.leanback.widget.ListRowPresenter! getListRowPresenter();
+    ctor public ListRowPresenter.ViewHolder(android.view.View, androidx.leanback.widget.HorizontalGridView, androidx.leanback.widget.ListRowPresenter);
+    method public final androidx.leanback.widget.ItemBridgeAdapter getBridgeAdapter();
+    method public final androidx.leanback.widget.HorizontalGridView getGridView();
+    method public androidx.leanback.widget.Presenter.ViewHolder? getItemViewHolder(int);
+    method public final androidx.leanback.widget.ListRowPresenter getListRowPresenter();
     method public int getSelectedPosition();
   }
 
@@ -2479,19 +2479,19 @@
   }
 
   public class PlaybackControlsRowPresenter extends androidx.leanback.widget.PlaybackRowPresenter {
-    ctor public PlaybackControlsRowPresenter(androidx.leanback.widget.Presenter!);
+    ctor public PlaybackControlsRowPresenter(androidx.leanback.widget.Presenter?);
     ctor public PlaybackControlsRowPresenter();
     method public boolean areSecondaryActionsHidden();
-    method protected androidx.leanback.widget.RowPresenter.ViewHolder! createRowViewHolder(android.view.ViewGroup!);
+    method protected androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
     method @ColorInt public int getBackgroundColor();
-    method public androidx.leanback.widget.OnActionClickedListener! getOnActionClickedListener();
+    method public androidx.leanback.widget.OnActionClickedListener? getOnActionClickedListener();
     method @ColorInt public int getProgressColor();
     method public void setBackgroundColor(@ColorInt int);
-    method public void setOnActionClickedListener(androidx.leanback.widget.OnActionClickedListener!);
+    method public void setOnActionClickedListener(androidx.leanback.widget.OnActionClickedListener?);
     method public void setProgressColor(@ColorInt int);
     method public void setSecondaryActionsHidden(boolean);
-    method public void showBottomSpace(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder!, boolean);
-    method public void showPrimaryActions(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder!);
+    method public void showBottomSpace(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder, boolean);
+    method public void showPrimaryActions(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder);
   }
 
   public class PlaybackControlsRowPresenter.ViewHolder extends androidx.leanback.widget.PlaybackRowPresenter.ViewHolder {
@@ -2500,7 +2500,7 @@
 
   public abstract class PlaybackRowPresenter extends androidx.leanback.widget.RowPresenter {
     ctor public PlaybackRowPresenter();
-    method public void onReappear(androidx.leanback.widget.RowPresenter.ViewHolder!);
+    method public void onReappear(androidx.leanback.widget.RowPresenter.ViewHolder);
   }
 
   public static class PlaybackRowPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
@@ -2561,12 +2561,12 @@
     ctor public Presenter();
     method protected static void cancelAnimationsRecursive(android.view.View!);
     method public final Object! getFacet(Class<?>!);
-    method public abstract void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
-    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!, java.util.List<java.lang.Object!>!);
-    method public abstract androidx.leanback.widget.Presenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method public abstract void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void onViewAttachedToWindow(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void onViewDetachedFromWindow(androidx.leanback.widget.Presenter.ViewHolder!);
+    method public abstract void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object);
+    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object, java.util.List<java.lang.Object!>);
+    method public abstract androidx.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public abstract void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
+    method public void onViewAttachedToWindow(androidx.leanback.widget.Presenter.ViewHolder);
+    method public void onViewDetachedFromWindow(androidx.leanback.widget.Presenter.ViewHolder);
     method public final void setFacet(Class<?>!, Object!);
     method public void setOnClickListener(androidx.leanback.widget.Presenter.ViewHolder!, android.view.View.OnClickListener!);
   }
@@ -2657,7 +2657,7 @@
 
   public abstract class RowPresenter extends androidx.leanback.widget.Presenter {
     ctor public RowPresenter();
-    method protected abstract androidx.leanback.widget.RowPresenter.ViewHolder! createRowViewHolder(android.view.ViewGroup!);
+    method protected abstract androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
     method protected void dispatchItemSelectedListener(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
     method public void freeze(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
     method public final androidx.leanback.widget.RowHeaderPresenter! getHeaderPresenter();
@@ -2668,19 +2668,19 @@
     method protected void initializeRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder!);
     method protected boolean isClippingChildren();
     method public boolean isUsingDefaultSelectEffect();
-    method protected void onBindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder!, Object!);
+    method protected void onBindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder, Object);
     method public final void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
     method public final androidx.leanback.widget.Presenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method protected void onRowViewAttachedToWindow(androidx.leanback.widget.RowPresenter.ViewHolder!);
-    method protected void onRowViewDetachedFromWindow(androidx.leanback.widget.RowPresenter.ViewHolder!);
+    method protected void onRowViewAttachedToWindow(androidx.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onRowViewDetachedFromWindow(androidx.leanback.widget.RowPresenter.ViewHolder);
     method protected void onRowViewExpanded(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
-    method protected void onRowViewSelected(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
+    method protected void onRowViewSelected(androidx.leanback.widget.RowPresenter.ViewHolder, boolean);
     method protected void onSelectLevelChanged(androidx.leanback.widget.RowPresenter.ViewHolder!);
-    method protected void onUnbindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder!);
+    method protected void onUnbindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder);
     method public final void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
     method public final void onViewAttachedToWindow(androidx.leanback.widget.Presenter.ViewHolder!);
     method public final void onViewDetachedFromWindow(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void setEntranceTransitionState(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
+    method public void setEntranceTransitionState(androidx.leanback.widget.RowPresenter.ViewHolder, boolean);
     method public final void setHeaderPresenter(androidx.leanback.widget.RowHeaderPresenter!);
     method public final void setRowViewExpanded(androidx.leanback.widget.Presenter.ViewHolder!, boolean);
     method public final void setRowViewSelected(androidx.leanback.widget.Presenter.ViewHolder!, boolean);
@@ -2702,8 +2702,8 @@
     method public final androidx.leanback.widget.Row! getRow();
     method public final Object! getRowObject();
     method public final float getSelectLevel();
-    method public Object! getSelectedItem();
-    method public androidx.leanback.widget.Presenter.ViewHolder! getSelectedItemViewHolder();
+    method public Object? getSelectedItem();
+    method public androidx.leanback.widget.Presenter.ViewHolder? getSelectedItemViewHolder();
     method public final boolean isExpanded();
     method public final boolean isSelected();
     method public final void setActivated(boolean);
@@ -2764,19 +2764,19 @@
   }
 
   public class SearchOrbView extends android.widget.FrameLayout implements android.view.View.OnClickListener {
-    ctor public SearchOrbView(android.content.Context!);
-    ctor public SearchOrbView(android.content.Context!, android.util.AttributeSet!);
-    ctor public SearchOrbView(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public SearchOrbView(android.content.Context);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet?);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet?, int);
     method public void enableOrbColorAnimation(boolean);
     method @ColorInt public int getOrbColor();
-    method public androidx.leanback.widget.SearchOrbView.Colors! getOrbColors();
-    method public android.graphics.drawable.Drawable! getOrbIcon();
+    method public androidx.leanback.widget.SearchOrbView.Colors? getOrbColors();
+    method public android.graphics.drawable.Drawable? getOrbIcon();
     method public void onClick(android.view.View!);
-    method public void setOnOrbClickedListener(android.view.View.OnClickListener!);
+    method public void setOnOrbClickedListener(android.view.View.OnClickListener?);
     method public void setOrbColor(int);
     method @Deprecated public void setOrbColor(@ColorInt int, @ColorInt int);
-    method public void setOrbColors(androidx.leanback.widget.SearchOrbView.Colors!);
-    method public void setOrbIcon(android.graphics.drawable.Drawable!);
+    method public void setOrbColors(androidx.leanback.widget.SearchOrbView.Colors);
+    method public void setOrbIcon(android.graphics.drawable.Drawable);
   }
 
   public static class SearchOrbView.Colors {
@@ -2904,19 +2904,19 @@
   }
 
   public class TitleView extends android.widget.FrameLayout implements androidx.leanback.widget.TitleViewAdapter.Provider {
-    ctor public TitleView(android.content.Context!);
-    ctor public TitleView(android.content.Context!, android.util.AttributeSet!);
-    ctor public TitleView(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public TitleView(android.content.Context);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet?);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet?, int);
     method public void enableAnimation(boolean);
-    method public android.graphics.drawable.Drawable! getBadgeDrawable();
-    method public androidx.leanback.widget.SearchOrbView.Colors! getSearchAffordanceColors();
-    method public android.view.View! getSearchAffordanceView();
-    method public CharSequence! getTitle();
-    method public androidx.leanback.widget.TitleViewAdapter! getTitleViewAdapter();
-    method public void setBadgeDrawable(android.graphics.drawable.Drawable!);
-    method public void setOnSearchClickedListener(android.view.View.OnClickListener!);
-    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors!);
-    method public void setTitle(CharSequence!);
+    method public android.graphics.drawable.Drawable? getBadgeDrawable();
+    method public androidx.leanback.widget.SearchOrbView.Colors? getSearchAffordanceColors();
+    method public android.view.View getSearchAffordanceView();
+    method public CharSequence? getTitle();
+    method public androidx.leanback.widget.TitleViewAdapter getTitleViewAdapter();
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable?);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener?);
+    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(CharSequence?);
     method public void updateComponentsVisibility(int);
   }
 
@@ -2995,35 +2995,35 @@
   }
 
   public class Picker extends android.widget.FrameLayout {
-    ctor public Picker(android.content.Context!, android.util.AttributeSet!);
-    ctor public Picker(android.content.Context!, android.util.AttributeSet!, int);
-    method public void addOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener!);
+    ctor public Picker(android.content.Context, android.util.AttributeSet?);
+    ctor public Picker(android.content.Context, android.util.AttributeSet?, int);
+    method public void addOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener);
     method public float getActivatedVisibleItemCount();
-    method public androidx.leanback.widget.picker.PickerColumn! getColumnAt(int);
+    method public androidx.leanback.widget.picker.PickerColumn? getColumnAt(int);
     method public int getColumnsCount();
     method protected int getPickerItemHeightPixels();
     method @LayoutRes public final int getPickerItemLayoutId();
     method @IdRes public final int getPickerItemTextViewId();
     method public int getSelectedColumn();
     method @Deprecated public final CharSequence! getSeparator();
-    method public final java.util.List<java.lang.CharSequence!>! getSeparators();
+    method public final java.util.List<java.lang.CharSequence!> getSeparators();
     method public float getVisibleItemCount();
     method public void onColumnValueChanged(int, int);
-    method public void removeOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener!);
+    method public void removeOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener);
     method public void setActivatedVisibleItemCount(float);
-    method public void setColumnAt(int, androidx.leanback.widget.picker.PickerColumn!);
+    method public void setColumnAt(int, androidx.leanback.widget.picker.PickerColumn);
     method public void setColumnValue(int, int, boolean);
-    method public void setColumns(java.util.List<androidx.leanback.widget.picker.PickerColumn!>!);
+    method public void setColumns(java.util.List<androidx.leanback.widget.picker.PickerColumn!>);
     method public final void setPickerItemLayoutId(@LayoutRes int);
     method public final void setPickerItemTextViewId(@IdRes int);
     method public void setSelectedColumn(int);
-    method public final void setSeparator(CharSequence!);
-    method public final void setSeparators(java.util.List<java.lang.CharSequence!>!);
+    method public final void setSeparator(CharSequence);
+    method public final void setSeparators(java.util.List<java.lang.CharSequence!>);
     method public void setVisibleItemCount(float);
   }
 
   public static interface Picker.PickerValueListener {
-    method public void onValueChanged(androidx.leanback.widget.picker.Picker!, int);
+    method public void onValueChanged(androidx.leanback.widget.picker.Picker, int);
   }
 
   public class PickerColumn {
diff --git a/leanback/leanback/api/public_plus_experimental_current.txt b/leanback/leanback/api/public_plus_experimental_current.txt
index fb9da3f..6cf18f9 100644
--- a/leanback/leanback/api/public_plus_experimental_current.txt
+++ b/leanback/leanback/api/public_plus_experimental_current.txt
@@ -509,10 +509,10 @@
     method public void notifyActionChanged(int);
     method public void notifyButtonActionChanged(int);
     method protected void onAddSharedElementTransition(androidx.fragment.app.FragmentTransaction, androidx.leanback.app.GuidedStepSupportFragment);
-    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
     method public android.view.View? onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
-    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
     method public androidx.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
     method public androidx.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
@@ -952,13 +952,13 @@
 
   public class VerticalGridSupportFragment extends androidx.leanback.app.BaseSupportFragment {
     ctor public VerticalGridSupportFragment();
-    method public androidx.leanback.widget.ObjectAdapter! getAdapter();
-    method public androidx.leanback.widget.VerticalGridPresenter! getGridPresenter();
-    method public androidx.leanback.widget.OnItemViewClickedListener! getOnItemViewClickedListener();
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter!);
-    method public void setGridPresenter(androidx.leanback.widget.VerticalGridPresenter!);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener!);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener!);
+    method public androidx.leanback.widget.ObjectAdapter? getAdapter();
+    method public androidx.leanback.widget.VerticalGridPresenter? getGridPresenter();
+    method public androidx.leanback.widget.OnItemViewClickedListener? getOnItemViewClickedListener();
+    method public void setAdapter(androidx.leanback.widget.ObjectAdapter?);
+    method public void setGridPresenter(androidx.leanback.widget.VerticalGridPresenter);
+    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener?);
+    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener?);
     method public void setSelectedPosition(int);
   }
 
@@ -1047,26 +1047,26 @@
 
   public class CompositeDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public CompositeDrawable();
-    method public void addChildDrawable(android.graphics.drawable.Drawable!);
-    method public void draw(android.graphics.Canvas!);
-    method public androidx.leanback.graphics.CompositeDrawable.ChildDrawable! getChildAt(int);
+    method public void addChildDrawable(android.graphics.drawable.Drawable);
+    method public void draw(android.graphics.Canvas);
+    method public androidx.leanback.graphics.CompositeDrawable.ChildDrawable getChildAt(int);
     method public int getChildCount();
-    method public android.graphics.drawable.Drawable! getDrawable(int);
+    method public android.graphics.drawable.Drawable getDrawable(int);
     method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable!);
+    method public void invalidateDrawable(android.graphics.drawable.Drawable);
     method public void removeChild(int);
-    method public void removeDrawable(android.graphics.drawable.Drawable!);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable!, Runnable!, long);
+    method public void removeDrawable(android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long);
     method public void setAlpha(int);
-    method public void setChildDrawableAt(int, android.graphics.drawable.Drawable!);
-    method public void setColorFilter(android.graphics.ColorFilter!);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable!, Runnable!);
+    method public void setChildDrawableAt(int, android.graphics.drawable.Drawable);
+    method public void setColorFilter(android.graphics.ColorFilter?);
+    method public void unscheduleDrawable(android.graphics.drawable.Drawable, Runnable);
   }
 
   public static final class CompositeDrawable.ChildDrawable {
-    ctor public CompositeDrawable.ChildDrawable(android.graphics.drawable.Drawable!, androidx.leanback.graphics.CompositeDrawable!);
-    method public androidx.leanback.graphics.BoundsRule! getBoundsRule();
-    method public android.graphics.drawable.Drawable! getDrawable();
+    ctor public CompositeDrawable.ChildDrawable(android.graphics.drawable.Drawable, androidx.leanback.graphics.CompositeDrawable);
+    method public androidx.leanback.graphics.BoundsRule getBoundsRule();
+    method public android.graphics.drawable.Drawable getDrawable();
     method public void recomputeBounds();
     field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable!,java.lang.Integer!>! BOTTOM_ABSOLUTE;
     field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable!,java.lang.Float!>! BOTTOM_FRACTION;
@@ -1392,17 +1392,17 @@
 
   public abstract class AbstractDetailsDescriptionPresenter extends androidx.leanback.widget.Presenter {
     ctor public AbstractDetailsDescriptionPresenter();
-    method protected abstract void onBindDescription(androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder!, Object!);
-    method public final void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
-    method public final androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
+    method protected abstract void onBindDescription(androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder, Object);
+    method public final void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object);
+    method public final androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
   }
 
   public static class AbstractDetailsDescriptionPresenter.ViewHolder extends androidx.leanback.widget.Presenter.ViewHolder {
-    ctor public AbstractDetailsDescriptionPresenter.ViewHolder(android.view.View!);
-    method public android.widget.TextView! getBody();
-    method public android.widget.TextView! getSubtitle();
-    method public android.widget.TextView! getTitle();
+    ctor public AbstractDetailsDescriptionPresenter.ViewHolder(android.view.View);
+    method public android.widget.TextView getBody();
+    method public android.widget.TextView getSubtitle();
+    method public android.widget.TextView getTitle();
   }
 
   public abstract class AbstractMediaItemPresenter extends androidx.leanback.widget.RowPresenter {
@@ -1462,20 +1462,20 @@
 
   public class Action {
     ctor public Action(long);
-    ctor public Action(long, CharSequence!);
-    ctor public Action(long, CharSequence!, CharSequence!);
-    ctor public Action(long, CharSequence!, CharSequence!, android.graphics.drawable.Drawable!);
+    ctor public Action(long, CharSequence?);
+    ctor public Action(long, CharSequence?, CharSequence?);
+    ctor public Action(long, CharSequence?, CharSequence?, android.graphics.drawable.Drawable?);
     method public final void addKeyCode(int);
-    method public final android.graphics.drawable.Drawable! getIcon();
+    method public final android.graphics.drawable.Drawable? getIcon();
     method public final long getId();
-    method public final CharSequence! getLabel1();
-    method public final CharSequence! getLabel2();
+    method public final CharSequence? getLabel1();
+    method public final CharSequence? getLabel2();
     method public final void removeKeyCode(int);
     method public final boolean respondsToKeyCode(int);
-    method public final void setIcon(android.graphics.drawable.Drawable!);
+    method public final void setIcon(android.graphics.drawable.Drawable?);
     method public final void setId(long);
-    method public final void setLabel1(CharSequence!);
-    method public final void setLabel2(CharSequence!);
+    method public final void setLabel1(CharSequence?);
+    method public final void setLabel2(CharSequence?);
     field public static final long NO_ID = -1L; // 0xffffffffffffffffL
   }
 
@@ -1597,22 +1597,22 @@
 
   public class DetailsOverviewLogoPresenter extends androidx.leanback.widget.Presenter {
     ctor public DetailsOverviewLogoPresenter();
-    method public boolean isBoundToImage(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder!, androidx.leanback.widget.DetailsOverviewRow!);
-    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
-    method public android.view.View! onCreateView(android.view.ViewGroup!);
-    method public androidx.leanback.widget.Presenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void setContext(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder!, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder!, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter!);
+    method public boolean isBoundToImage(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, androidx.leanback.widget.DetailsOverviewRow?);
+    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object);
+    method public android.view.View onCreateView(android.view.ViewGroup);
+    method public androidx.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
+    method public void setContext(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder?, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter?);
   }
 
   public static class DetailsOverviewLogoPresenter.ViewHolder extends androidx.leanback.widget.Presenter.ViewHolder {
-    ctor public DetailsOverviewLogoPresenter.ViewHolder(android.view.View!);
-    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter! getParentPresenter();
-    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder! getParentViewHolder();
+    ctor public DetailsOverviewLogoPresenter.ViewHolder(android.view.View);
+    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter? getParentPresenter();
+    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder? getParentViewHolder();
     method public boolean isSizeFromDrawableIntrinsic();
     method public void setSizeFromDrawableIntrinsic(boolean);
-    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter! mParentPresenter;
-    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder! mParentViewHolder;
+    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter? mParentPresenter;
+    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder? mParentViewHolder;
   }
 
   public class DetailsOverviewRow extends androidx.leanback.widget.Row {
@@ -1793,16 +1793,16 @@
     ctor protected GuidedAction();
     method public String![]! getAutofillHints();
     method public int getCheckSetId();
-    method public CharSequence! getDescription();
+    method public CharSequence? getDescription();
     method public int getDescriptionEditInputType();
     method public int getDescriptionInputType();
-    method public CharSequence! getEditDescription();
+    method public CharSequence? getEditDescription();
     method public int getEditInputType();
-    method public CharSequence! getEditTitle();
+    method public CharSequence? getEditTitle();
     method public int getInputType();
-    method public android.content.Intent! getIntent();
-    method public java.util.List<androidx.leanback.widget.GuidedAction!>! getSubActions();
-    method public CharSequence! getTitle();
+    method public android.content.Intent? getIntent();
+    method public java.util.List<androidx.leanback.widget.GuidedAction!>? getSubActions();
+    method public CharSequence? getTitle();
     method public boolean hasEditableActivatorView();
     method public boolean hasMultilineDescription();
     method public boolean hasNext();
@@ -1816,17 +1816,17 @@
     method public boolean isEditable();
     method public boolean isEnabled();
     method public boolean isFocusable();
-    method public void onRestoreInstanceState(android.os.Bundle!, String!);
-    method public void onSaveInstanceState(android.os.Bundle!, String!);
+    method public void onRestoreInstanceState(android.os.Bundle, String);
+    method public void onSaveInstanceState(android.os.Bundle, String);
     method public void setChecked(boolean);
-    method public void setDescription(CharSequence!);
-    method public void setEditDescription(CharSequence!);
-    method public void setEditTitle(CharSequence!);
+    method public void setDescription(CharSequence?);
+    method public void setEditDescription(CharSequence?);
+    method public void setEditTitle(CharSequence?);
     method public void setEnabled(boolean);
     method public void setFocusable(boolean);
-    method public void setIntent(android.content.Intent!);
-    method public void setSubActions(java.util.List<androidx.leanback.widget.GuidedAction!>!);
-    method public void setTitle(CharSequence!);
+    method public void setIntent(android.content.Intent?);
+    method public void setSubActions(java.util.List<androidx.leanback.widget.GuidedAction!>?);
+    method public void setTitle(CharSequence?);
     field public static final long ACTION_ID_CANCEL = -5L; // 0xfffffffffffffffbL
     field public static final long ACTION_ID_CONTINUE = -7L; // 0xfffffffffffffff9L
     field public static final long ACTION_ID_CURRENT = -3L; // 0xfffffffffffffffdL
@@ -1842,44 +1842,44 @@
 
   public static class GuidedAction.Builder extends androidx.leanback.widget.GuidedAction.BuilderBase<androidx.leanback.widget.GuidedAction.Builder> {
     ctor @Deprecated public GuidedAction.Builder();
-    ctor public GuidedAction.Builder(android.content.Context!);
-    method public androidx.leanback.widget.GuidedAction! build();
+    ctor public GuidedAction.Builder(android.content.Context?);
+    method public androidx.leanback.widget.GuidedAction build();
   }
 
   public abstract static class GuidedAction.BuilderBase<B extends androidx.leanback.widget.GuidedAction.BuilderBase> {
-    ctor public GuidedAction.BuilderBase(android.content.Context!);
-    method protected final void applyValues(androidx.leanback.widget.GuidedAction!);
+    ctor public GuidedAction.BuilderBase(android.content.Context);
+    method protected final void applyValues(androidx.leanback.widget.GuidedAction);
     method public B! autoSaveRestoreEnabled(boolean);
     method public B! autofillHints(java.lang.String!...);
     method public B! checkSetId(int);
     method public B! checked(boolean);
     method public B! clickAction(long);
-    method public B! description(CharSequence!);
+    method public B! description(CharSequence?);
     method public B! description(@StringRes int);
     method public B! descriptionEditInputType(int);
     method public B! descriptionEditable(boolean);
     method public B! descriptionInputType(int);
-    method public B! editDescription(CharSequence!);
+    method public B! editDescription(CharSequence?);
     method public B! editDescription(@StringRes int);
     method public B! editInputType(int);
-    method public B! editTitle(CharSequence!);
+    method public B! editTitle(CharSequence?);
     method public B! editTitle(@StringRes int);
     method public B! editable(boolean);
     method public B! enabled(boolean);
     method public B! focusable(boolean);
-    method public android.content.Context! getContext();
+    method public android.content.Context getContext();
     method public B! hasEditableActivatorView(boolean);
     method public B! hasNext(boolean);
-    method public B! icon(android.graphics.drawable.Drawable!);
+    method public B! icon(android.graphics.drawable.Drawable?);
     method public B! icon(@DrawableRes int);
     method @Deprecated public B! iconResourceId(@DrawableRes int, android.content.Context!);
     method public B! id(long);
     method public B! infoOnly(boolean);
     method public B! inputType(int);
-    method public B! intent(android.content.Intent!);
+    method public B! intent(android.content.Intent?);
     method public B! multilineDescription(boolean);
-    method public B! subActions(java.util.List<androidx.leanback.widget.GuidedAction!>!);
-    method public B! title(CharSequence!);
+    method public B! subActions(java.util.List<androidx.leanback.widget.GuidedAction!>?);
+    method public B! title(CharSequence?);
     method public B! title(@StringRes int);
   }
 
@@ -2167,19 +2167,19 @@
   public static class ListRowPresenter.SelectItemViewHolderTask extends androidx.leanback.widget.Presenter.ViewHolderTask {
     ctor public ListRowPresenter.SelectItemViewHolderTask(int);
     method public int getItemPosition();
-    method public androidx.leanback.widget.Presenter.ViewHolderTask! getItemTask();
+    method public androidx.leanback.widget.Presenter.ViewHolderTask? getItemTask();
     method public boolean isSmoothScroll();
     method public void setItemPosition(int);
-    method public void setItemTask(androidx.leanback.widget.Presenter.ViewHolderTask!);
+    method public void setItemTask(androidx.leanback.widget.Presenter.ViewHolderTask?);
     method public void setSmoothScroll(boolean);
   }
 
   public static class ListRowPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
-    ctor public ListRowPresenter.ViewHolder(android.view.View!, androidx.leanback.widget.HorizontalGridView!, androidx.leanback.widget.ListRowPresenter!);
-    method public final androidx.leanback.widget.ItemBridgeAdapter! getBridgeAdapter();
-    method public final androidx.leanback.widget.HorizontalGridView! getGridView();
-    method public androidx.leanback.widget.Presenter.ViewHolder! getItemViewHolder(int);
-    method public final androidx.leanback.widget.ListRowPresenter! getListRowPresenter();
+    ctor public ListRowPresenter.ViewHolder(android.view.View, androidx.leanback.widget.HorizontalGridView, androidx.leanback.widget.ListRowPresenter);
+    method public final androidx.leanback.widget.ItemBridgeAdapter getBridgeAdapter();
+    method public final androidx.leanback.widget.HorizontalGridView getGridView();
+    method public androidx.leanback.widget.Presenter.ViewHolder? getItemViewHolder(int);
+    method public final androidx.leanback.widget.ListRowPresenter getListRowPresenter();
     method public int getSelectedPosition();
   }
 
@@ -2479,19 +2479,19 @@
   }
 
   public class PlaybackControlsRowPresenter extends androidx.leanback.widget.PlaybackRowPresenter {
-    ctor public PlaybackControlsRowPresenter(androidx.leanback.widget.Presenter!);
+    ctor public PlaybackControlsRowPresenter(androidx.leanback.widget.Presenter?);
     ctor public PlaybackControlsRowPresenter();
     method public boolean areSecondaryActionsHidden();
-    method protected androidx.leanback.widget.RowPresenter.ViewHolder! createRowViewHolder(android.view.ViewGroup!);
+    method protected androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
     method @ColorInt public int getBackgroundColor();
-    method public androidx.leanback.widget.OnActionClickedListener! getOnActionClickedListener();
+    method public androidx.leanback.widget.OnActionClickedListener? getOnActionClickedListener();
     method @ColorInt public int getProgressColor();
     method public void setBackgroundColor(@ColorInt int);
-    method public void setOnActionClickedListener(androidx.leanback.widget.OnActionClickedListener!);
+    method public void setOnActionClickedListener(androidx.leanback.widget.OnActionClickedListener?);
     method public void setProgressColor(@ColorInt int);
     method public void setSecondaryActionsHidden(boolean);
-    method public void showBottomSpace(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder!, boolean);
-    method public void showPrimaryActions(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder!);
+    method public void showBottomSpace(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder, boolean);
+    method public void showPrimaryActions(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder);
   }
 
   public class PlaybackControlsRowPresenter.ViewHolder extends androidx.leanback.widget.PlaybackRowPresenter.ViewHolder {
@@ -2500,7 +2500,7 @@
 
   public abstract class PlaybackRowPresenter extends androidx.leanback.widget.RowPresenter {
     ctor public PlaybackRowPresenter();
-    method public void onReappear(androidx.leanback.widget.RowPresenter.ViewHolder!);
+    method public void onReappear(androidx.leanback.widget.RowPresenter.ViewHolder);
   }
 
   public static class PlaybackRowPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
@@ -2561,12 +2561,12 @@
     ctor public Presenter();
     method protected static void cancelAnimationsRecursive(android.view.View!);
     method public final Object! getFacet(Class<?>!);
-    method public abstract void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
-    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!, java.util.List<java.lang.Object!>!);
-    method public abstract androidx.leanback.widget.Presenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method public abstract void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void onViewAttachedToWindow(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void onViewDetachedFromWindow(androidx.leanback.widget.Presenter.ViewHolder!);
+    method public abstract void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object);
+    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object, java.util.List<java.lang.Object!>);
+    method public abstract androidx.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public abstract void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
+    method public void onViewAttachedToWindow(androidx.leanback.widget.Presenter.ViewHolder);
+    method public void onViewDetachedFromWindow(androidx.leanback.widget.Presenter.ViewHolder);
     method public final void setFacet(Class<?>!, Object!);
     method public void setOnClickListener(androidx.leanback.widget.Presenter.ViewHolder!, android.view.View.OnClickListener!);
   }
@@ -2657,7 +2657,7 @@
 
   public abstract class RowPresenter extends androidx.leanback.widget.Presenter {
     ctor public RowPresenter();
-    method protected abstract androidx.leanback.widget.RowPresenter.ViewHolder! createRowViewHolder(android.view.ViewGroup!);
+    method protected abstract androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
     method protected void dispatchItemSelectedListener(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
     method public void freeze(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
     method public final androidx.leanback.widget.RowHeaderPresenter! getHeaderPresenter();
@@ -2668,19 +2668,19 @@
     method protected void initializeRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder!);
     method protected boolean isClippingChildren();
     method public boolean isUsingDefaultSelectEffect();
-    method protected void onBindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder!, Object!);
+    method protected void onBindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder, Object);
     method public final void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
     method public final androidx.leanback.widget.Presenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method protected void onRowViewAttachedToWindow(androidx.leanback.widget.RowPresenter.ViewHolder!);
-    method protected void onRowViewDetachedFromWindow(androidx.leanback.widget.RowPresenter.ViewHolder!);
+    method protected void onRowViewAttachedToWindow(androidx.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onRowViewDetachedFromWindow(androidx.leanback.widget.RowPresenter.ViewHolder);
     method protected void onRowViewExpanded(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
-    method protected void onRowViewSelected(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
+    method protected void onRowViewSelected(androidx.leanback.widget.RowPresenter.ViewHolder, boolean);
     method protected void onSelectLevelChanged(androidx.leanback.widget.RowPresenter.ViewHolder!);
-    method protected void onUnbindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder!);
+    method protected void onUnbindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder);
     method public final void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
     method public final void onViewAttachedToWindow(androidx.leanback.widget.Presenter.ViewHolder!);
     method public final void onViewDetachedFromWindow(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void setEntranceTransitionState(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
+    method public void setEntranceTransitionState(androidx.leanback.widget.RowPresenter.ViewHolder, boolean);
     method public final void setHeaderPresenter(androidx.leanback.widget.RowHeaderPresenter!);
     method public final void setRowViewExpanded(androidx.leanback.widget.Presenter.ViewHolder!, boolean);
     method public final void setRowViewSelected(androidx.leanback.widget.Presenter.ViewHolder!, boolean);
@@ -2702,8 +2702,8 @@
     method public final androidx.leanback.widget.Row! getRow();
     method public final Object! getRowObject();
     method public final float getSelectLevel();
-    method public Object! getSelectedItem();
-    method public androidx.leanback.widget.Presenter.ViewHolder! getSelectedItemViewHolder();
+    method public Object? getSelectedItem();
+    method public androidx.leanback.widget.Presenter.ViewHolder? getSelectedItemViewHolder();
     method public final boolean isExpanded();
     method public final boolean isSelected();
     method public final void setActivated(boolean);
@@ -2764,19 +2764,19 @@
   }
 
   public class SearchOrbView extends android.widget.FrameLayout implements android.view.View.OnClickListener {
-    ctor public SearchOrbView(android.content.Context!);
-    ctor public SearchOrbView(android.content.Context!, android.util.AttributeSet!);
-    ctor public SearchOrbView(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public SearchOrbView(android.content.Context);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet?);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet?, int);
     method public void enableOrbColorAnimation(boolean);
     method @ColorInt public int getOrbColor();
-    method public androidx.leanback.widget.SearchOrbView.Colors! getOrbColors();
-    method public android.graphics.drawable.Drawable! getOrbIcon();
+    method public androidx.leanback.widget.SearchOrbView.Colors? getOrbColors();
+    method public android.graphics.drawable.Drawable? getOrbIcon();
     method public void onClick(android.view.View!);
-    method public void setOnOrbClickedListener(android.view.View.OnClickListener!);
+    method public void setOnOrbClickedListener(android.view.View.OnClickListener?);
     method public void setOrbColor(int);
     method @Deprecated public void setOrbColor(@ColorInt int, @ColorInt int);
-    method public void setOrbColors(androidx.leanback.widget.SearchOrbView.Colors!);
-    method public void setOrbIcon(android.graphics.drawable.Drawable!);
+    method public void setOrbColors(androidx.leanback.widget.SearchOrbView.Colors);
+    method public void setOrbIcon(android.graphics.drawable.Drawable);
   }
 
   public static class SearchOrbView.Colors {
@@ -2904,19 +2904,19 @@
   }
 
   public class TitleView extends android.widget.FrameLayout implements androidx.leanback.widget.TitleViewAdapter.Provider {
-    ctor public TitleView(android.content.Context!);
-    ctor public TitleView(android.content.Context!, android.util.AttributeSet!);
-    ctor public TitleView(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public TitleView(android.content.Context);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet?);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet?, int);
     method public void enableAnimation(boolean);
-    method public android.graphics.drawable.Drawable! getBadgeDrawable();
-    method public androidx.leanback.widget.SearchOrbView.Colors! getSearchAffordanceColors();
-    method public android.view.View! getSearchAffordanceView();
-    method public CharSequence! getTitle();
-    method public androidx.leanback.widget.TitleViewAdapter! getTitleViewAdapter();
-    method public void setBadgeDrawable(android.graphics.drawable.Drawable!);
-    method public void setOnSearchClickedListener(android.view.View.OnClickListener!);
-    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors!);
-    method public void setTitle(CharSequence!);
+    method public android.graphics.drawable.Drawable? getBadgeDrawable();
+    method public androidx.leanback.widget.SearchOrbView.Colors? getSearchAffordanceColors();
+    method public android.view.View getSearchAffordanceView();
+    method public CharSequence? getTitle();
+    method public androidx.leanback.widget.TitleViewAdapter getTitleViewAdapter();
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable?);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener?);
+    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(CharSequence?);
     method public void updateComponentsVisibility(int);
   }
 
@@ -2995,35 +2995,35 @@
   }
 
   public class Picker extends android.widget.FrameLayout {
-    ctor public Picker(android.content.Context!, android.util.AttributeSet!);
-    ctor public Picker(android.content.Context!, android.util.AttributeSet!, int);
-    method public void addOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener!);
+    ctor public Picker(android.content.Context, android.util.AttributeSet?);
+    ctor public Picker(android.content.Context, android.util.AttributeSet?, int);
+    method public void addOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener);
     method public float getActivatedVisibleItemCount();
-    method public androidx.leanback.widget.picker.PickerColumn! getColumnAt(int);
+    method public androidx.leanback.widget.picker.PickerColumn? getColumnAt(int);
     method public int getColumnsCount();
     method protected int getPickerItemHeightPixels();
     method @LayoutRes public final int getPickerItemLayoutId();
     method @IdRes public final int getPickerItemTextViewId();
     method public int getSelectedColumn();
     method @Deprecated public final CharSequence! getSeparator();
-    method public final java.util.List<java.lang.CharSequence!>! getSeparators();
+    method public final java.util.List<java.lang.CharSequence!> getSeparators();
     method public float getVisibleItemCount();
     method public void onColumnValueChanged(int, int);
-    method public void removeOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener!);
+    method public void removeOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener);
     method public void setActivatedVisibleItemCount(float);
-    method public void setColumnAt(int, androidx.leanback.widget.picker.PickerColumn!);
+    method public void setColumnAt(int, androidx.leanback.widget.picker.PickerColumn);
     method public void setColumnValue(int, int, boolean);
-    method public void setColumns(java.util.List<androidx.leanback.widget.picker.PickerColumn!>!);
+    method public void setColumns(java.util.List<androidx.leanback.widget.picker.PickerColumn!>);
     method public final void setPickerItemLayoutId(@LayoutRes int);
     method public final void setPickerItemTextViewId(@IdRes int);
     method public void setSelectedColumn(int);
-    method public final void setSeparator(CharSequence!);
-    method public final void setSeparators(java.util.List<java.lang.CharSequence!>!);
+    method public final void setSeparator(CharSequence);
+    method public final void setSeparators(java.util.List<java.lang.CharSequence!>);
     method public void setVisibleItemCount(float);
   }
 
   public static interface Picker.PickerValueListener {
-    method public void onValueChanged(androidx.leanback.widget.picker.Picker!, int);
+    method public void onValueChanged(androidx.leanback.widget.picker.Picker, int);
   }
 
   public class PickerColumn {
diff --git a/leanback/leanback/api/restricted_current.txt b/leanback/leanback/api/restricted_current.txt
index c42b7de..5011866 100644
--- a/leanback/leanback/api/restricted_current.txt
+++ b/leanback/leanback/api/restricted_current.txt
@@ -539,10 +539,10 @@
     method public void notifyActionChanged(int);
     method public void notifyButtonActionChanged(int);
     method protected void onAddSharedElementTransition(androidx.fragment.app.FragmentTransaction, androidx.leanback.app.GuidedStepSupportFragment);
-    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateActionsStylist();
     method public android.view.View? onCreateBackgroundView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
-    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle);
+    method public void onCreateButtonActions(java.util.List<androidx.leanback.widget.GuidedAction!>, android.os.Bundle?);
     method public androidx.leanback.widget.GuidedActionsStylist onCreateButtonActionsStylist();
     method public androidx.leanback.widget.GuidanceStylist.Guidance onCreateGuidance(android.os.Bundle);
     method public androidx.leanback.widget.GuidanceStylist onCreateGuidanceStylist();
@@ -993,13 +993,13 @@
 
   public class VerticalGridSupportFragment extends androidx.leanback.app.BaseSupportFragment {
     ctor public VerticalGridSupportFragment();
-    method public androidx.leanback.widget.ObjectAdapter! getAdapter();
-    method public androidx.leanback.widget.VerticalGridPresenter! getGridPresenter();
-    method public androidx.leanback.widget.OnItemViewClickedListener! getOnItemViewClickedListener();
-    method public void setAdapter(androidx.leanback.widget.ObjectAdapter!);
-    method public void setGridPresenter(androidx.leanback.widget.VerticalGridPresenter!);
-    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener!);
-    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener!);
+    method public androidx.leanback.widget.ObjectAdapter? getAdapter();
+    method public androidx.leanback.widget.VerticalGridPresenter? getGridPresenter();
+    method public androidx.leanback.widget.OnItemViewClickedListener? getOnItemViewClickedListener();
+    method public void setAdapter(androidx.leanback.widget.ObjectAdapter?);
+    method public void setGridPresenter(androidx.leanback.widget.VerticalGridPresenter);
+    method public void setOnItemViewClickedListener(androidx.leanback.widget.OnItemViewClickedListener?);
+    method public void setOnItemViewSelectedListener(androidx.leanback.widget.OnItemViewSelectedListener?);
     method public void setSelectedPosition(int);
   }
 
@@ -1088,26 +1088,26 @@
 
   public class CompositeDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
     ctor public CompositeDrawable();
-    method public void addChildDrawable(android.graphics.drawable.Drawable!);
-    method public void draw(android.graphics.Canvas!);
-    method public androidx.leanback.graphics.CompositeDrawable.ChildDrawable! getChildAt(int);
+    method public void addChildDrawable(android.graphics.drawable.Drawable);
+    method public void draw(android.graphics.Canvas);
+    method public androidx.leanback.graphics.CompositeDrawable.ChildDrawable getChildAt(int);
     method public int getChildCount();
-    method public android.graphics.drawable.Drawable! getDrawable(int);
+    method public android.graphics.drawable.Drawable getDrawable(int);
     method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable!);
+    method public void invalidateDrawable(android.graphics.drawable.Drawable);
     method public void removeChild(int);
-    method public void removeDrawable(android.graphics.drawable.Drawable!);
-    method public void scheduleDrawable(android.graphics.drawable.Drawable!, Runnable!, long);
+    method public void removeDrawable(android.graphics.drawable.Drawable);
+    method public void scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long);
     method public void setAlpha(int);
-    method public void setChildDrawableAt(int, android.graphics.drawable.Drawable!);
-    method public void setColorFilter(android.graphics.ColorFilter!);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable!, Runnable!);
+    method public void setChildDrawableAt(int, android.graphics.drawable.Drawable);
+    method public void setColorFilter(android.graphics.ColorFilter?);
+    method public void unscheduleDrawable(android.graphics.drawable.Drawable, Runnable);
   }
 
   public static final class CompositeDrawable.ChildDrawable {
-    ctor public CompositeDrawable.ChildDrawable(android.graphics.drawable.Drawable!, androidx.leanback.graphics.CompositeDrawable!);
-    method public androidx.leanback.graphics.BoundsRule! getBoundsRule();
-    method public android.graphics.drawable.Drawable! getDrawable();
+    ctor public CompositeDrawable.ChildDrawable(android.graphics.drawable.Drawable, androidx.leanback.graphics.CompositeDrawable);
+    method public androidx.leanback.graphics.BoundsRule getBoundsRule();
+    method public android.graphics.drawable.Drawable getDrawable();
     method public void recomputeBounds();
     field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable!,java.lang.Integer!>! BOTTOM_ABSOLUTE;
     field public static final android.util.Property<androidx.leanback.graphics.CompositeDrawable.ChildDrawable!,java.lang.Float!>! BOTTOM_FRACTION;
@@ -1543,17 +1543,17 @@
 
   public abstract class AbstractDetailsDescriptionPresenter extends androidx.leanback.widget.Presenter {
     ctor public AbstractDetailsDescriptionPresenter();
-    method protected abstract void onBindDescription(androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder!, Object!);
-    method public final void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
-    method public final androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
+    method protected abstract void onBindDescription(androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder, Object);
+    method public final void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object);
+    method public final androidx.leanback.widget.AbstractDetailsDescriptionPresenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
   }
 
   public static class AbstractDetailsDescriptionPresenter.ViewHolder extends androidx.leanback.widget.Presenter.ViewHolder {
-    ctor public AbstractDetailsDescriptionPresenter.ViewHolder(android.view.View!);
-    method public android.widget.TextView! getBody();
-    method public android.widget.TextView! getSubtitle();
-    method public android.widget.TextView! getTitle();
+    ctor public AbstractDetailsDescriptionPresenter.ViewHolder(android.view.View);
+    method public android.widget.TextView getBody();
+    method public android.widget.TextView getSubtitle();
+    method public android.widget.TextView getTitle();
   }
 
   public abstract class AbstractMediaItemPresenter extends androidx.leanback.widget.RowPresenter {
@@ -1613,20 +1613,20 @@
 
   public class Action {
     ctor public Action(long);
-    ctor public Action(long, CharSequence!);
-    ctor public Action(long, CharSequence!, CharSequence!);
-    ctor public Action(long, CharSequence!, CharSequence!, android.graphics.drawable.Drawable!);
+    ctor public Action(long, CharSequence?);
+    ctor public Action(long, CharSequence?, CharSequence?);
+    ctor public Action(long, CharSequence?, CharSequence?, android.graphics.drawable.Drawable?);
     method public final void addKeyCode(int);
-    method public final android.graphics.drawable.Drawable! getIcon();
+    method public final android.graphics.drawable.Drawable? getIcon();
     method public final long getId();
-    method public final CharSequence! getLabel1();
-    method public final CharSequence! getLabel2();
+    method public final CharSequence? getLabel1();
+    method public final CharSequence? getLabel2();
     method public final void removeKeyCode(int);
     method public final boolean respondsToKeyCode(int);
-    method public final void setIcon(android.graphics.drawable.Drawable!);
+    method public final void setIcon(android.graphics.drawable.Drawable?);
     method public final void setId(long);
-    method public final void setLabel1(CharSequence!);
-    method public final void setLabel2(CharSequence!);
+    method public final void setLabel1(CharSequence?);
+    method public final void setLabel2(CharSequence?);
     field public static final long NO_ID = -1L; // 0xffffffffffffffffL
   }
 
@@ -1758,22 +1758,22 @@
 
   public class DetailsOverviewLogoPresenter extends androidx.leanback.widget.Presenter {
     ctor public DetailsOverviewLogoPresenter();
-    method public boolean isBoundToImage(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder!, androidx.leanback.widget.DetailsOverviewRow!);
-    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
-    method public android.view.View! onCreateView(android.view.ViewGroup!);
-    method public androidx.leanback.widget.Presenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void setContext(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder!, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder!, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter!);
+    method public boolean isBoundToImage(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, androidx.leanback.widget.DetailsOverviewRow?);
+    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object);
+    method public android.view.View onCreateView(android.view.ViewGroup);
+    method public androidx.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
+    method public void setContext(androidx.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder?, androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter?);
   }
 
   public static class DetailsOverviewLogoPresenter.ViewHolder extends androidx.leanback.widget.Presenter.ViewHolder {
-    ctor public DetailsOverviewLogoPresenter.ViewHolder(android.view.View!);
-    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter! getParentPresenter();
-    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder! getParentViewHolder();
+    ctor public DetailsOverviewLogoPresenter.ViewHolder(android.view.View);
+    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter? getParentPresenter();
+    method public androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder? getParentViewHolder();
     method public boolean isSizeFromDrawableIntrinsic();
     method public void setSizeFromDrawableIntrinsic(boolean);
-    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter! mParentPresenter;
-    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder! mParentViewHolder;
+    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter? mParentPresenter;
+    field protected androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder? mParentViewHolder;
   }
 
   public class DetailsOverviewRow extends androidx.leanback.widget.Row {
@@ -1955,16 +1955,16 @@
     ctor protected GuidedAction();
     method public String![]! getAutofillHints();
     method public int getCheckSetId();
-    method public CharSequence! getDescription();
+    method public CharSequence? getDescription();
     method public int getDescriptionEditInputType();
     method public int getDescriptionInputType();
-    method public CharSequence! getEditDescription();
+    method public CharSequence? getEditDescription();
     method public int getEditInputType();
-    method public CharSequence! getEditTitle();
+    method public CharSequence? getEditTitle();
     method public int getInputType();
-    method public android.content.Intent! getIntent();
-    method public java.util.List<androidx.leanback.widget.GuidedAction!>! getSubActions();
-    method public CharSequence! getTitle();
+    method public android.content.Intent? getIntent();
+    method public java.util.List<androidx.leanback.widget.GuidedAction!>? getSubActions();
+    method public CharSequence? getTitle();
     method public boolean hasEditableActivatorView();
     method public boolean hasMultilineDescription();
     method public boolean hasNext();
@@ -1978,17 +1978,17 @@
     method public boolean isEditable();
     method public boolean isEnabled();
     method public boolean isFocusable();
-    method public void onRestoreInstanceState(android.os.Bundle!, String!);
-    method public void onSaveInstanceState(android.os.Bundle!, String!);
+    method public void onRestoreInstanceState(android.os.Bundle, String);
+    method public void onSaveInstanceState(android.os.Bundle, String);
     method public void setChecked(boolean);
-    method public void setDescription(CharSequence!);
-    method public void setEditDescription(CharSequence!);
-    method public void setEditTitle(CharSequence!);
+    method public void setDescription(CharSequence?);
+    method public void setEditDescription(CharSequence?);
+    method public void setEditTitle(CharSequence?);
     method public void setEnabled(boolean);
     method public void setFocusable(boolean);
-    method public void setIntent(android.content.Intent!);
-    method public void setSubActions(java.util.List<androidx.leanback.widget.GuidedAction!>!);
-    method public void setTitle(CharSequence!);
+    method public void setIntent(android.content.Intent?);
+    method public void setSubActions(java.util.List<androidx.leanback.widget.GuidedAction!>?);
+    method public void setTitle(CharSequence?);
     field public static final long ACTION_ID_CANCEL = -5L; // 0xfffffffffffffffbL
     field public static final long ACTION_ID_CONTINUE = -7L; // 0xfffffffffffffff9L
     field public static final long ACTION_ID_CURRENT = -3L; // 0xfffffffffffffffdL
@@ -2004,44 +2004,44 @@
 
   public static class GuidedAction.Builder extends androidx.leanback.widget.GuidedAction.BuilderBase<androidx.leanback.widget.GuidedAction.Builder> {
     ctor @Deprecated public GuidedAction.Builder();
-    ctor public GuidedAction.Builder(android.content.Context!);
-    method public androidx.leanback.widget.GuidedAction! build();
+    ctor public GuidedAction.Builder(android.content.Context?);
+    method public androidx.leanback.widget.GuidedAction build();
   }
 
   public abstract static class GuidedAction.BuilderBase<B extends androidx.leanback.widget.GuidedAction.BuilderBase> {
-    ctor public GuidedAction.BuilderBase(android.content.Context!);
-    method protected final void applyValues(androidx.leanback.widget.GuidedAction!);
+    ctor public GuidedAction.BuilderBase(android.content.Context);
+    method protected final void applyValues(androidx.leanback.widget.GuidedAction);
     method public B! autoSaveRestoreEnabled(boolean);
     method public B! autofillHints(java.lang.String!...);
     method public B! checkSetId(int);
     method public B! checked(boolean);
     method public B! clickAction(long);
-    method public B! description(CharSequence!);
+    method public B! description(CharSequence?);
     method public B! description(@StringRes int);
     method public B! descriptionEditInputType(int);
     method public B! descriptionEditable(boolean);
     method public B! descriptionInputType(int);
-    method public B! editDescription(CharSequence!);
+    method public B! editDescription(CharSequence?);
     method public B! editDescription(@StringRes int);
     method public B! editInputType(int);
-    method public B! editTitle(CharSequence!);
+    method public B! editTitle(CharSequence?);
     method public B! editTitle(@StringRes int);
     method public B! editable(boolean);
     method public B! enabled(boolean);
     method public B! focusable(boolean);
-    method public android.content.Context! getContext();
+    method public android.content.Context getContext();
     method public B! hasEditableActivatorView(boolean);
     method public B! hasNext(boolean);
-    method public B! icon(android.graphics.drawable.Drawable!);
+    method public B! icon(android.graphics.drawable.Drawable?);
     method public B! icon(@DrawableRes int);
     method @Deprecated public B! iconResourceId(@DrawableRes int, android.content.Context!);
     method public B! id(long);
     method public B! infoOnly(boolean);
     method public B! inputType(int);
-    method public B! intent(android.content.Intent!);
+    method public B! intent(android.content.Intent?);
     method public B! multilineDescription(boolean);
-    method public B! subActions(java.util.List<androidx.leanback.widget.GuidedAction!>!);
-    method public B! title(CharSequence!);
+    method public B! subActions(java.util.List<androidx.leanback.widget.GuidedAction!>?);
+    method public B! title(CharSequence?);
     method public B! title(@StringRes int);
   }
 
@@ -2081,13 +2081,13 @@
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class GuidedActionAdapterGroup {
     ctor public GuidedActionAdapterGroup();
-    method public void addAdpter(androidx.leanback.widget.GuidedActionAdapter!, androidx.leanback.widget.GuidedActionAdapter!);
-    method public void closeIme(android.view.View!);
-    method public void fillAndGoNext(androidx.leanback.widget.GuidedActionAdapter!, android.widget.TextView!);
-    method public void fillAndStay(androidx.leanback.widget.GuidedActionAdapter!, android.widget.TextView!);
-    method public androidx.leanback.widget.GuidedActionAdapter! getNextAdapter(androidx.leanback.widget.GuidedActionAdapter!);
-    method public void openIme(androidx.leanback.widget.GuidedActionAdapter!, androidx.leanback.widget.GuidedActionsStylist.ViewHolder!);
-    method public void setEditListener(androidx.leanback.widget.GuidedActionAdapter.EditListener!);
+    method public void addAdpter(androidx.leanback.widget.GuidedActionAdapter?, androidx.leanback.widget.GuidedActionAdapter?);
+    method public void closeIme(android.view.View);
+    method public void fillAndGoNext(androidx.leanback.widget.GuidedActionAdapter, android.widget.TextView);
+    method public void fillAndStay(androidx.leanback.widget.GuidedActionAdapter, android.widget.TextView);
+    method public androidx.leanback.widget.GuidedActionAdapter? getNextAdapter(androidx.leanback.widget.GuidedActionAdapter);
+    method public void openIme(androidx.leanback.widget.GuidedActionAdapter, androidx.leanback.widget.GuidedActionsStylist.ViewHolder);
+    method public void setEditListener(androidx.leanback.widget.GuidedActionAdapter.EditListener?);
   }
 
   public interface GuidedActionAutofillSupport {
@@ -2380,19 +2380,19 @@
   public static class ListRowPresenter.SelectItemViewHolderTask extends androidx.leanback.widget.Presenter.ViewHolderTask {
     ctor public ListRowPresenter.SelectItemViewHolderTask(int);
     method public int getItemPosition();
-    method public androidx.leanback.widget.Presenter.ViewHolderTask! getItemTask();
+    method public androidx.leanback.widget.Presenter.ViewHolderTask? getItemTask();
     method public boolean isSmoothScroll();
     method public void setItemPosition(int);
-    method public void setItemTask(androidx.leanback.widget.Presenter.ViewHolderTask!);
+    method public void setItemTask(androidx.leanback.widget.Presenter.ViewHolderTask?);
     method public void setSmoothScroll(boolean);
   }
 
   public static class ListRowPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
-    ctor public ListRowPresenter.ViewHolder(android.view.View!, androidx.leanback.widget.HorizontalGridView!, androidx.leanback.widget.ListRowPresenter!);
-    method public final androidx.leanback.widget.ItemBridgeAdapter! getBridgeAdapter();
-    method public final androidx.leanback.widget.HorizontalGridView! getGridView();
-    method public androidx.leanback.widget.Presenter.ViewHolder! getItemViewHolder(int);
-    method public final androidx.leanback.widget.ListRowPresenter! getListRowPresenter();
+    ctor public ListRowPresenter.ViewHolder(android.view.View, androidx.leanback.widget.HorizontalGridView, androidx.leanback.widget.ListRowPresenter);
+    method public final androidx.leanback.widget.ItemBridgeAdapter getBridgeAdapter();
+    method public final androidx.leanback.widget.HorizontalGridView getGridView();
+    method public androidx.leanback.widget.Presenter.ViewHolder? getItemViewHolder(int);
+    method public final androidx.leanback.widget.ListRowPresenter getListRowPresenter();
     method public int getSelectedPosition();
   }
 
@@ -2727,19 +2727,19 @@
   }
 
   public class PlaybackControlsRowPresenter extends androidx.leanback.widget.PlaybackRowPresenter {
-    ctor public PlaybackControlsRowPresenter(androidx.leanback.widget.Presenter!);
+    ctor public PlaybackControlsRowPresenter(androidx.leanback.widget.Presenter?);
     ctor public PlaybackControlsRowPresenter();
     method public boolean areSecondaryActionsHidden();
-    method protected androidx.leanback.widget.RowPresenter.ViewHolder! createRowViewHolder(android.view.ViewGroup!);
+    method protected androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
     method @ColorInt public int getBackgroundColor();
-    method public androidx.leanback.widget.OnActionClickedListener! getOnActionClickedListener();
+    method public androidx.leanback.widget.OnActionClickedListener? getOnActionClickedListener();
     method @ColorInt public int getProgressColor();
     method public void setBackgroundColor(@ColorInt int);
-    method public void setOnActionClickedListener(androidx.leanback.widget.OnActionClickedListener!);
+    method public void setOnActionClickedListener(androidx.leanback.widget.OnActionClickedListener?);
     method public void setProgressColor(@ColorInt int);
     method public void setSecondaryActionsHidden(boolean);
-    method public void showBottomSpace(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder!, boolean);
-    method public void showPrimaryActions(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder!);
+    method public void showBottomSpace(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder, boolean);
+    method public void showPrimaryActions(androidx.leanback.widget.PlaybackControlsRowPresenter.ViewHolder);
   }
 
   public class PlaybackControlsRowPresenter.ViewHolder extends androidx.leanback.widget.PlaybackRowPresenter.ViewHolder {
@@ -2748,7 +2748,7 @@
 
   public abstract class PlaybackRowPresenter extends androidx.leanback.widget.RowPresenter {
     ctor public PlaybackRowPresenter();
-    method public void onReappear(androidx.leanback.widget.RowPresenter.ViewHolder!);
+    method public void onReappear(androidx.leanback.widget.RowPresenter.ViewHolder);
   }
 
   public static class PlaybackRowPresenter.ViewHolder extends androidx.leanback.widget.RowPresenter.ViewHolder {
@@ -2818,12 +2818,12 @@
     ctor public Presenter();
     method protected static void cancelAnimationsRecursive(android.view.View!);
     method public final Object! getFacet(Class<?>!);
-    method public abstract void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
-    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!, java.util.List<java.lang.Object!>!);
-    method public abstract androidx.leanback.widget.Presenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method public abstract void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void onViewAttachedToWindow(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void onViewDetachedFromWindow(androidx.leanback.widget.Presenter.ViewHolder!);
+    method public abstract void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object);
+    method public void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder, Object, java.util.List<java.lang.Object!>);
+    method public abstract androidx.leanback.widget.Presenter.ViewHolder onCreateViewHolder(android.view.ViewGroup);
+    method public abstract void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder);
+    method public void onViewAttachedToWindow(androidx.leanback.widget.Presenter.ViewHolder);
+    method public void onViewDetachedFromWindow(androidx.leanback.widget.Presenter.ViewHolder);
     method public final void setFacet(Class<?>!, Object!);
     method public void setOnClickListener(androidx.leanback.widget.Presenter.ViewHolder!, android.view.View.OnClickListener!);
   }
@@ -2917,7 +2917,7 @@
 
   public abstract class RowPresenter extends androidx.leanback.widget.Presenter {
     ctor public RowPresenter();
-    method protected abstract androidx.leanback.widget.RowPresenter.ViewHolder! createRowViewHolder(android.view.ViewGroup!);
+    method protected abstract androidx.leanback.widget.RowPresenter.ViewHolder createRowViewHolder(android.view.ViewGroup);
     method protected void dispatchItemSelectedListener(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
     method public void freeze(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
     method public final androidx.leanback.widget.RowHeaderPresenter! getHeaderPresenter();
@@ -2928,19 +2928,19 @@
     method protected void initializeRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder!);
     method protected boolean isClippingChildren();
     method public boolean isUsingDefaultSelectEffect();
-    method protected void onBindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder!, Object!);
+    method protected void onBindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder, Object);
     method public final void onBindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!, Object!);
     method public final androidx.leanback.widget.Presenter.ViewHolder! onCreateViewHolder(android.view.ViewGroup!);
-    method protected void onRowViewAttachedToWindow(androidx.leanback.widget.RowPresenter.ViewHolder!);
-    method protected void onRowViewDetachedFromWindow(androidx.leanback.widget.RowPresenter.ViewHolder!);
+    method protected void onRowViewAttachedToWindow(androidx.leanback.widget.RowPresenter.ViewHolder);
+    method protected void onRowViewDetachedFromWindow(androidx.leanback.widget.RowPresenter.ViewHolder);
     method protected void onRowViewExpanded(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
-    method protected void onRowViewSelected(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
+    method protected void onRowViewSelected(androidx.leanback.widget.RowPresenter.ViewHolder, boolean);
     method protected void onSelectLevelChanged(androidx.leanback.widget.RowPresenter.ViewHolder!);
-    method protected void onUnbindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder!);
+    method protected void onUnbindRowViewHolder(androidx.leanback.widget.RowPresenter.ViewHolder);
     method public final void onUnbindViewHolder(androidx.leanback.widget.Presenter.ViewHolder!);
     method public final void onViewAttachedToWindow(androidx.leanback.widget.Presenter.ViewHolder!);
     method public final void onViewDetachedFromWindow(androidx.leanback.widget.Presenter.ViewHolder!);
-    method public void setEntranceTransitionState(androidx.leanback.widget.RowPresenter.ViewHolder!, boolean);
+    method public void setEntranceTransitionState(androidx.leanback.widget.RowPresenter.ViewHolder, boolean);
     method public final void setHeaderPresenter(androidx.leanback.widget.RowHeaderPresenter!);
     method public final void setRowViewExpanded(androidx.leanback.widget.Presenter.ViewHolder!, boolean);
     method public final void setRowViewSelected(androidx.leanback.widget.Presenter.ViewHolder!, boolean);
@@ -2962,8 +2962,8 @@
     method public final androidx.leanback.widget.Row! getRow();
     method public final Object! getRowObject();
     method public final float getSelectLevel();
-    method public Object! getSelectedItem();
-    method public androidx.leanback.widget.Presenter.ViewHolder! getSelectedItemViewHolder();
+    method public Object? getSelectedItem();
+    method public androidx.leanback.widget.Presenter.ViewHolder? getSelectedItemViewHolder();
     method public final boolean isExpanded();
     method public final boolean isSelected();
     method public final void setActivated(boolean);
@@ -3033,19 +3033,19 @@
   }
 
   public class SearchOrbView extends android.widget.FrameLayout implements android.view.View.OnClickListener {
-    ctor public SearchOrbView(android.content.Context!);
-    ctor public SearchOrbView(android.content.Context!, android.util.AttributeSet!);
-    ctor public SearchOrbView(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public SearchOrbView(android.content.Context);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet?);
+    ctor public SearchOrbView(android.content.Context, android.util.AttributeSet?, int);
     method public void enableOrbColorAnimation(boolean);
     method @ColorInt public int getOrbColor();
-    method public androidx.leanback.widget.SearchOrbView.Colors! getOrbColors();
-    method public android.graphics.drawable.Drawable! getOrbIcon();
+    method public androidx.leanback.widget.SearchOrbView.Colors? getOrbColors();
+    method public android.graphics.drawable.Drawable? getOrbIcon();
     method public void onClick(android.view.View!);
-    method public void setOnOrbClickedListener(android.view.View.OnClickListener!);
+    method public void setOnOrbClickedListener(android.view.View.OnClickListener?);
     method public void setOrbColor(int);
     method @Deprecated public void setOrbColor(@ColorInt int, @ColorInt int);
-    method public void setOrbColors(androidx.leanback.widget.SearchOrbView.Colors!);
-    method public void setOrbIcon(android.graphics.drawable.Drawable!);
+    method public void setOrbColors(androidx.leanback.widget.SearchOrbView.Colors);
+    method public void setOrbIcon(android.graphics.drawable.Drawable);
   }
 
   public static class SearchOrbView.Colors {
@@ -3210,19 +3210,19 @@
   }
 
   public class TitleView extends android.widget.FrameLayout implements androidx.leanback.widget.TitleViewAdapter.Provider {
-    ctor public TitleView(android.content.Context!);
-    ctor public TitleView(android.content.Context!, android.util.AttributeSet!);
-    ctor public TitleView(android.content.Context!, android.util.AttributeSet!, int);
+    ctor public TitleView(android.content.Context);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet?);
+    ctor public TitleView(android.content.Context, android.util.AttributeSet?, int);
     method public void enableAnimation(boolean);
-    method public android.graphics.drawable.Drawable! getBadgeDrawable();
-    method public androidx.leanback.widget.SearchOrbView.Colors! getSearchAffordanceColors();
-    method public android.view.View! getSearchAffordanceView();
-    method public CharSequence! getTitle();
-    method public androidx.leanback.widget.TitleViewAdapter! getTitleViewAdapter();
-    method public void setBadgeDrawable(android.graphics.drawable.Drawable!);
-    method public void setOnSearchClickedListener(android.view.View.OnClickListener!);
-    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors!);
-    method public void setTitle(CharSequence!);
+    method public android.graphics.drawable.Drawable? getBadgeDrawable();
+    method public androidx.leanback.widget.SearchOrbView.Colors? getSearchAffordanceColors();
+    method public android.view.View getSearchAffordanceView();
+    method public CharSequence? getTitle();
+    method public androidx.leanback.widget.TitleViewAdapter getTitleViewAdapter();
+    method public void setBadgeDrawable(android.graphics.drawable.Drawable?);
+    method public void setOnSearchClickedListener(android.view.View.OnClickListener?);
+    method public void setSearchAffordanceColors(androidx.leanback.widget.SearchOrbView.Colors);
+    method public void setTitle(CharSequence?);
     method public void updateComponentsVisibility(int);
   }
 
@@ -3305,35 +3305,35 @@
   }
 
   public class Picker extends android.widget.FrameLayout {
-    ctor public Picker(android.content.Context!, android.util.AttributeSet!);
-    ctor public Picker(android.content.Context!, android.util.AttributeSet!, int);
-    method public void addOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener!);
+    ctor public Picker(android.content.Context, android.util.AttributeSet?);
+    ctor public Picker(android.content.Context, android.util.AttributeSet?, int);
+    method public void addOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener);
     method public float getActivatedVisibleItemCount();
-    method public androidx.leanback.widget.picker.PickerColumn! getColumnAt(int);
+    method public androidx.leanback.widget.picker.PickerColumn? getColumnAt(int);
     method public int getColumnsCount();
     method protected int getPickerItemHeightPixels();
     method @LayoutRes public final int getPickerItemLayoutId();
     method @IdRes public final int getPickerItemTextViewId();
     method public int getSelectedColumn();
     method @Deprecated public final CharSequence! getSeparator();
-    method public final java.util.List<java.lang.CharSequence!>! getSeparators();
+    method public final java.util.List<java.lang.CharSequence!> getSeparators();
     method public float getVisibleItemCount();
     method public void onColumnValueChanged(int, int);
-    method public void removeOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener!);
+    method public void removeOnValueChangedListener(androidx.leanback.widget.picker.Picker.PickerValueListener);
     method public void setActivatedVisibleItemCount(float);
-    method public void setColumnAt(int, androidx.leanback.widget.picker.PickerColumn!);
+    method public void setColumnAt(int, androidx.leanback.widget.picker.PickerColumn);
     method public void setColumnValue(int, int, boolean);
-    method public void setColumns(java.util.List<androidx.leanback.widget.picker.PickerColumn!>!);
+    method public void setColumns(java.util.List<androidx.leanback.widget.picker.PickerColumn!>);
     method public final void setPickerItemLayoutId(@LayoutRes int);
     method public final void setPickerItemTextViewId(@IdRes int);
     method public void setSelectedColumn(int);
-    method public final void setSeparator(CharSequence!);
-    method public final void setSeparators(java.util.List<java.lang.CharSequence!>!);
+    method public final void setSeparator(CharSequence);
+    method public final void setSeparators(java.util.List<java.lang.CharSequence!>);
     method public void setVisibleItemCount(float);
   }
 
   public static interface Picker.PickerValueListener {
-    method public void onValueChanged(androidx.leanback.widget.picker.Picker!, int);
+    method public void onValueChanged(androidx.leanback.widget.picker.Picker, int);
   }
 
   public class PickerColumn {
diff --git a/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsTestFragment.java b/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsTestFragment.java
index 3dc6fd7..bdd1698 100644
--- a/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsTestFragment.java
+++ b/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsTestFragment.java
@@ -23,6 +23,7 @@
 import android.os.Handler;
 import android.view.ViewGroup;
 
+import androidx.annotation.NonNull;
 import androidx.leanback.test.R;
 import androidx.leanback.widget.AbstractDetailsDescriptionPresenter;
 import androidx.leanback.widget.Action;
@@ -91,7 +92,7 @@
                 new FullWidthDetailsOverviewRowPresenter(new AbstractDetailsDescriptionPresenter() {
                     @Override
                     protected void onBindDescription(
-                            AbstractDetailsDescriptionPresenter.ViewHolder vh, Object item) {
+                            @NonNull AbstractDetailsDescriptionPresenter.ViewHolder vh, @NonNull Object item) {
                         vh.getTitle().setText("Funny Movie");
                         vh.getSubtitle().setText("Android TV Production Inc.");
                         vh.getBody().setText("What a great movie!");
diff --git a/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsTestSupportFragment.java b/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsTestSupportFragment.java
index c08d5c1..fc598f7 100644
--- a/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsTestSupportFragment.java
+++ b/leanback/leanback/src/androidTest/java/androidx/leanback/app/DetailsTestSupportFragment.java
@@ -20,6 +20,7 @@
 import android.os.Handler;
 import android.view.ViewGroup;
 
+import androidx.annotation.NonNull;
 import androidx.leanback.test.R;
 import androidx.leanback.widget.AbstractDetailsDescriptionPresenter;
 import androidx.leanback.widget.Action;
@@ -88,7 +89,9 @@
                 new FullWidthDetailsOverviewRowPresenter(new AbstractDetailsDescriptionPresenter() {
                     @Override
                     protected void onBindDescription(
-                            AbstractDetailsDescriptionPresenter.ViewHolder vh, Object item) {
+                            @NonNull AbstractDetailsDescriptionPresenter.ViewHolder vh,
+                            @NonNull Object item
+                    ) {
                         vh.getTitle().setText("Funny Movie");
                         vh.getSubtitle().setText("Android TV Production Inc.");
                         vh.getBody().setText("What a great movie!");
diff --git a/leanback/leanback/src/androidTest/java/androidx/leanback/widget/PresenterTest.java b/leanback/leanback/src/androidTest/java/androidx/leanback/widget/PresenterTest.java
index 9c168fe..2b519c8 100644
--- a/leanback/leanback/src/androidTest/java/androidx/leanback/widget/PresenterTest.java
+++ b/leanback/leanback/src/androidTest/java/androidx/leanback/widget/PresenterTest.java
@@ -27,6 +27,7 @@
 import android.view.ViewGroup.LayoutParams;
 import android.widget.FrameLayout;
 
+import androidx.annotation.NonNull;
 import androidx.leanback.R;
 import androidx.leanback.app.HeadersFragment;
 import androidx.test.core.app.ApplicationProvider;
@@ -146,7 +147,7 @@
         Context context = new ContextThemeWrapper(mContext, R.style.Theme_Leanback);
         Presenter detailsPresenter = new AbstractDetailsDescriptionPresenter() {
             @Override
-            protected void onBindDescription(ViewHolder vh, Object item) {
+            protected void onBindDescription(@NonNull ViewHolder vh, @NonNull Object item) {
                 vh.getTitle().setText("The quick brown fox jumped over the lazy dog");
                 vh.getSubtitle().setText("Subtitle");
             }
diff --git a/leanback/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java b/leanback/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java
index 927e8a3..e3ab902 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java
@@ -337,7 +337,7 @@
      */
     public void onCreateActions(
             @NonNull List<GuidedAction> actions,
-            @NonNull Bundle savedInstanceState
+            @Nullable Bundle savedInstanceState
     ) {
     }
 
@@ -349,7 +349,7 @@
      */
     public void onCreateButtonActions(
             @NonNull List<GuidedAction> actions,
-            @NonNull Bundle savedInstanceState
+            @Nullable Bundle savedInstanceState
     ) {
     }
 
diff --git a/leanback/leanback/src/main/java/androidx/leanback/app/VerticalGridSupportFragment.java b/leanback/leanback/src/main/java/androidx/leanback/app/VerticalGridSupportFragment.java
index 26b9a648..764f988 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/app/VerticalGridSupportFragment.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/app/VerticalGridSupportFragment.java
@@ -19,6 +19,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.leanback.R;
 import androidx.leanback.transition.TransitionHelper;
 import androidx.leanback.util.StateMachine.State;
@@ -76,7 +78,7 @@
     /**
      * Sets the grid presenter.
      */
-    public void setGridPresenter(VerticalGridPresenter gridPresenter) {
+    public void setGridPresenter(@NonNull VerticalGridPresenter gridPresenter) {
         if (gridPresenter == null) {
             throw new IllegalArgumentException("Grid presenter may not be null");
         }
@@ -90,6 +92,7 @@
     /**
      * Returns the grid presenter.
      */
+    @Nullable
     public VerticalGridPresenter getGridPresenter() {
         return mGridPresenter;
     }
@@ -97,7 +100,7 @@
     /**
      * Sets the object adapter for the fragment.
      */
-    public void setAdapter(ObjectAdapter adapter) {
+    public void setAdapter(@Nullable ObjectAdapter adapter) {
         mAdapter = adapter;
         updateAdapter();
     }
@@ -105,6 +108,7 @@
     /**
      * Returns the object adapter.
      */
+    @Nullable
     public ObjectAdapter getAdapter() {
         return mAdapter;
     }
@@ -127,7 +131,12 @@
     final private OnChildLaidOutListener mChildLaidOutListener =
             new OnChildLaidOutListener() {
         @Override
-        public void onChildLaidOut(ViewGroup parent, View view, int position, long id) {
+        public void onChildLaidOut(
+                @NonNull ViewGroup parent,
+                @NonNull View view,
+                int position,
+                long id
+        ) {
             if (position == 0) {
                 showOrHideTitle();
             }
@@ -137,7 +146,7 @@
     /**
      * Sets an item selection listener.
      */
-    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
+    public void setOnItemViewSelectedListener(@Nullable OnItemViewSelectedListener listener) {
         mOnItemViewSelectedListener = listener;
     }
 
@@ -163,7 +172,7 @@
     /**
      * Sets an item clicked listener.
      */
-    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
+    public void setOnItemViewClickedListener(@Nullable OnItemViewClickedListener listener) {
         mOnItemViewClickedListener = listener;
         if (mGridPresenter != null) {
             mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
@@ -173,13 +182,15 @@
     /**
      * Returns the item clicked listener.
      */
+    @Nullable
     public OnItemViewClickedListener getOnItemViewClickedListener() {
         return mOnItemViewClickedListener;
     }
 
     @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
+    @NonNull
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
         ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_vertical_grid_fragment,
                 container, false);
         ViewGroup gridFrame = (ViewGroup) root.findViewById(R.id.grid_frame);
@@ -242,13 +253,14 @@
     }
 
     @Override
+    @NonNull
     protected Object createEntranceTransition() {
         return TransitionHelper.loadTransition(getContext(),
                 R.transition.lb_vertical_grid_entrance_transition);
     }
 
     @Override
-    protected void runEntranceTransition(Object entranceTransition) {
+    protected void runEntranceTransition(@Nullable Object entranceTransition) {
         TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
     }
 
diff --git a/leanback/leanback/src/main/java/androidx/leanback/graphics/CompositeDrawable.java b/leanback/leanback/src/main/java/androidx/leanback/graphics/CompositeDrawable.java
index 196b94a..0b0b320 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/graphics/CompositeDrawable.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/graphics/CompositeDrawable.java
@@ -24,6 +24,7 @@
 import android.util.Property;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.core.graphics.drawable.DrawableCompat;
 import androidx.leanback.graphics.BoundsRule.ValueRule;
 
@@ -76,11 +77,13 @@
     }
 
     @Override
+    @NonNull
     public ConstantState getConstantState() {
         return mState;
     }
 
     @Override
+    @NonNull
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
             mState = new CompositeState(mState, this, null);
@@ -99,20 +102,21 @@
     /**
      * Adds the supplied region.
      */
-    public void addChildDrawable(Drawable drawable) {
+    public void addChildDrawable(@NonNull Drawable drawable) {
         mState.mChildren.add(new ChildDrawable(drawable, this));
     }
 
     /**
      * Sets the supplied region at given index.
      */
-    public void setChildDrawableAt(int index, Drawable drawable) {
+    public void setChildDrawableAt(int index, @NonNull Drawable drawable) {
         mState.mChildren.set(index, new ChildDrawable(drawable, this));
     }
 
     /**
      * Returns the {@link Drawable} for the given index.
      */
+    @NonNull
     public Drawable getDrawable(int index) {
         return mState.mChildren.get(index).mDrawable;
     }
@@ -120,6 +124,7 @@
     /**
      * Returns the {@link ChildDrawable} at the given index.
      */
+    @NonNull
     public ChildDrawable getChildAt(int index) {
         return mState.mChildren.get(index);
     }
@@ -134,7 +139,7 @@
     /**
      * Removes the given region.
      */
-    public void removeDrawable(Drawable drawable) {
+    public void removeDrawable(@NonNull Drawable drawable) {
         final ArrayList<ChildDrawable> children = mState.mChildren;
         for (int i = 0; i < children.size(); i++) {
             if (drawable == children.get(i).mDrawable) {
@@ -153,7 +158,7 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
+    public void draw(@NonNull Canvas canvas) {
         final ArrayList<ChildDrawable> children = mState.mChildren;
         for (int i = 0; i < children.size(); i++) {
             children.get(i).mDrawable.draw(canvas);
@@ -167,7 +172,7 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter colorFilter) {
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
         final ArrayList<ChildDrawable> children = mState.mChildren;
         for (int i = 0; i < children.size(); i++) {
             children.get(i).mDrawable.setColorFilter(colorFilter);
@@ -212,17 +217,17 @@
     }
 
     @Override
-    public void invalidateDrawable(Drawable who) {
+    public void invalidateDrawable(@NonNull Drawable who) {
         invalidateSelf();
     }
 
     @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+    public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
         scheduleSelf(what, when);
     }
 
     @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
+    public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
         unscheduleSelf(what);
     }
 
@@ -247,7 +252,7 @@
         private final Rect adjustedBounds = new Rect();
         final CompositeDrawable mParent;
 
-        public ChildDrawable(Drawable drawable, CompositeDrawable parent) {
+        public ChildDrawable(@NonNull Drawable drawable, @NonNull CompositeDrawable parent) {
             this.mDrawable = drawable;
             this.mParent = parent;
             this.mBoundsRule = new BoundsRule();
@@ -283,6 +288,7 @@
         /**
          * Returns the instance of {@link BoundsRule}.
          */
+        @NonNull
         public BoundsRule getBoundsRule() {
             return this.mBoundsRule;
         }
@@ -290,6 +296,7 @@
         /**
          * Returns the {@link Drawable}.
          */
+        @NonNull
         public Drawable getDrawable() {
             return mDrawable;
         }
diff --git a/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackBannerControlGlue.java b/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackBannerControlGlue.java
index 84d4f61..d701f4f 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackBannerControlGlue.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackBannerControlGlue.java
@@ -325,8 +325,8 @@
         final AbstractDetailsDescriptionPresenter detailsPresenter =
                 new AbstractDetailsDescriptionPresenter() {
                     @Override
-                    protected void onBindDescription(ViewHolder
-                            viewHolder, Object object) {
+                    protected void onBindDescription(@NonNull ViewHolder
+                            viewHolder, @NonNull Object object) {
                         PlaybackBannerControlGlue glue = (PlaybackBannerControlGlue) object;
                         viewHolder.getTitle().setText(glue.getTitle());
                         viewHolder.getSubtitle().setText(glue.getSubtitle());
diff --git a/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackControlGlue.java b/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackControlGlue.java
index 70df6ab..fdbc134 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackControlGlue.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackControlGlue.java
@@ -24,6 +24,7 @@
 import android.view.KeyEvent;
 import android.view.View;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.leanback.widget.AbstractDetailsDescriptionPresenter;
 import androidx.leanback.widget.Action;
@@ -280,8 +281,8 @@
             final AbstractDetailsDescriptionPresenter detailsPresenter =
                     new AbstractDetailsDescriptionPresenter() {
                         @Override
-                        protected void onBindDescription(ViewHolder
-                                viewHolder, Object object) {
+                        protected void onBindDescription(@NonNull ViewHolder
+                                viewHolder, @NonNull Object object) {
                             PlaybackControlGlue glue = (PlaybackControlGlue) object;
                             if (glue.hasValidMedia()) {
                                 viewHolder.getTitle().setText(glue.getMediaTitle());
diff --git a/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackTransportControlGlue.java b/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackTransportControlGlue.java
index 29388a8..e1de03d 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackTransportControlGlue.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/media/PlaybackTransportControlGlue.java
@@ -23,6 +23,7 @@
 import android.view.KeyEvent;
 import android.view.View;
 
+import androidx.annotation.NonNull;
 import androidx.leanback.widget.AbstractDetailsDescriptionPresenter;
 import androidx.leanback.widget.Action;
 import androidx.leanback.widget.ArrayObjectAdapter;
@@ -142,8 +143,8 @@
         final AbstractDetailsDescriptionPresenter detailsPresenter =
                 new AbstractDetailsDescriptionPresenter() {
                     @Override
-                    protected void onBindDescription(ViewHolder
-                            viewHolder, Object obj) {
+                    protected void onBindDescription(@NonNull ViewHolder
+                            viewHolder, @NonNull Object obj) {
                         PlaybackBaseControlGlue glue = (PlaybackBaseControlGlue) obj;
                         viewHolder.getTitle().setText(glue.getTitle());
                         viewHolder.getSubtitle().setText(glue.getSubtitle());
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/AbstractDetailsDescriptionPresenter.java b/leanback/leanback/src/main/java/androidx/leanback/widget/AbstractDetailsDescriptionPresenter.java
index ce3ef92..e518e75 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/AbstractDetailsDescriptionPresenter.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/AbstractDetailsDescriptionPresenter.java
@@ -22,6 +22,7 @@
 import android.view.ViewTreeObserver;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
 import androidx.leanback.R;
 
 /**
@@ -54,7 +55,7 @@
         final int mTitleMaxLines;
         private ViewTreeObserver.OnPreDrawListener mPreDrawListener;
 
-        public ViewHolder(final View view) {
+        public ViewHolder(final @NonNull View view) {
             super(view);
             mTitle = (TextView) view.findViewById(R.id.lb_details_description_title);
             mSubtitle = (TextView) view.findViewById(R.id.lb_details_description_subtitle);
@@ -129,14 +130,17 @@
             }
         }
 
+        @NonNull
         public TextView getTitle() {
             return mTitle;
         }
 
+        @NonNull
         public TextView getSubtitle() {
             return mSubtitle;
         }
 
+        @NonNull
         public TextView getBody() {
             return mBody;
         }
@@ -150,14 +154,18 @@
     }
 
     @Override
-    public final ViewHolder onCreateViewHolder(ViewGroup parent) {
+    @NonNull
+    public final ViewHolder onCreateViewHolder(@NonNull ViewGroup parent) {
         View v = LayoutInflater.from(parent.getContext())
             .inflate(R.layout.lb_details_description, parent, false);
         return new ViewHolder(v);
     }
 
     @Override
-    public final void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
+    public final void onBindViewHolder(
+            @NonNull Presenter.ViewHolder viewHolder,
+            @NonNull Object item
+    ) {
         ViewHolder vh = (ViewHolder) viewHolder;
         onBindDescription(vh, item);
 
@@ -213,13 +221,13 @@
      * @param vh The ViewHolder for this details description view.
      * @param item The item being presented.
      */
-    protected abstract void onBindDescription(ViewHolder vh, Object item);
+    protected abstract void onBindDescription(@NonNull ViewHolder vh, @NonNull Object item);
 
     @Override
-    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {}
+    public void onUnbindViewHolder(@NonNull Presenter.ViewHolder viewHolder) {}
 
     @Override
-    public void onViewAttachedToWindow(Presenter.ViewHolder holder) {
+    public void onViewAttachedToWindow(@NonNull Presenter.ViewHolder holder) {
         // In case predraw listener was removed in detach, make sure
         // we have the proper layout.
         ViewHolder vh = (ViewHolder) holder;
@@ -228,7 +236,7 @@
     }
 
     @Override
-    public void onViewDetachedFromWindow(Presenter.ViewHolder holder) {
+    public void onViewDetachedFromWindow(@NonNull Presenter.ViewHolder holder) {
         ViewHolder vh = (ViewHolder) holder;
         vh.removePreDrawListener();
         super.onViewDetachedFromWindow(holder);
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/Action.java b/leanback/leanback/src/main/java/androidx/leanback/widget/Action.java
index 6bc38ef..33f49e2 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/Action.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/Action.java
@@ -16,6 +16,9 @@
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import java.util.ArrayList;
 
 /**
@@ -48,7 +51,7 @@
      * @param id The id of the Action.
      * @param label The label to display for the Action.
      */
-    public Action(long id, CharSequence label) {
+    public Action(long id, @Nullable CharSequence label) {
         this(id, label, null);
     }
 
@@ -59,7 +62,7 @@
      * @param label1 The label to display on the first line of the Action.
      * @param label2 The label to display on the second line of the Action.
      */
-    public Action(long id, CharSequence label1, CharSequence label2) {
+    public Action(long id, @Nullable CharSequence label1, @Nullable CharSequence label2) {
         this(id, label1, label2, null);
     }
 
@@ -71,7 +74,12 @@
      * @param label2 The label to display on the second line of the Action.
      * @param icon The icon to display for the Action.
      */
-    public Action(long id, CharSequence label1, CharSequence label2, Drawable icon) {
+    public Action(
+            long id,
+            @Nullable CharSequence label1,
+            @Nullable CharSequence label2,
+            @Nullable Drawable icon
+    ) {
         setId(id);
         setLabel1(label1);
         setLabel2(label2);
@@ -95,13 +103,14 @@
     /**
      * Sets the first line label for this Action.
      */
-    public final void setLabel1(CharSequence label) {
+    public final void setLabel1(@Nullable CharSequence label) {
         mLabel1 = label;
     }
 
     /**
      * Returns the first line label for this Action.
      */
+    @Nullable
     public final CharSequence getLabel1() {
         return mLabel1;
     }
@@ -109,13 +118,14 @@
     /**
      * Sets the second line label for this Action.
      */
-    public final void setLabel2(CharSequence label) {
+    public final void setLabel2(@Nullable CharSequence label) {
         mLabel2 = label;
     }
 
     /**
      * Returns the second line label for this Action.
      */
+    @Nullable
     public final CharSequence getLabel2() {
         return mLabel2;
     }
@@ -123,13 +133,14 @@
     /**
      * Sets the icon drawable for this Action.
      */
-    public final void setIcon(Drawable icon) {
+    public final void setIcon(@Nullable Drawable icon) {
         mIcon = icon;
     }
 
     /**
      * Returns the icon drawable for this Action.
      */
+    @Nullable
     public final Drawable getIcon() {
         return mIcon;
     }
@@ -156,6 +167,7 @@
     }
 
     @Override
+    @NonNull
     public String toString(){
         StringBuilder sb = new StringBuilder();
         if (!TextUtils.isEmpty(mLabel1)) {
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/DetailsOverviewLogoPresenter.java b/leanback/leanback/src/main/java/androidx/leanback/widget/DetailsOverviewLogoPresenter.java
index e2017b3..6f62961 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/DetailsOverviewLogoPresenter.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/DetailsOverviewLogoPresenter.java
@@ -5,6 +5,8 @@
 import android.view.ViewGroup;
 import android.widget.ImageView;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.leanback.R;
 
 /**
@@ -29,18 +31,22 @@
      */
     public static class ViewHolder extends Presenter.ViewHolder {
 
+        @Nullable
         protected FullWidthDetailsOverviewRowPresenter mParentPresenter;
+        @Nullable
         protected FullWidthDetailsOverviewRowPresenter.ViewHolder mParentViewHolder;
         private boolean mSizeFromDrawableIntrinsic;
 
-        public ViewHolder(View view) {
+        public ViewHolder(@NonNull View view) {
             super(view);
         }
 
+        @Nullable
         public FullWidthDetailsOverviewRowPresenter getParentPresenter() {
             return mParentPresenter;
         }
 
+        @Nullable
         public FullWidthDetailsOverviewRowPresenter.ViewHolder getParentViewHolder() {
             return mParentViewHolder;
         }
@@ -84,13 +90,15 @@
      * @param parent Parent view.
      * @return View created for the logo.
      */
-    public View onCreateView(ViewGroup parent) {
+    @NonNull
+    public View onCreateView(@NonNull ViewGroup parent) {
         return LayoutInflater.from(parent.getContext())
                 .inflate(R.layout.lb_fullwidth_details_overview_logo, parent, false);
     }
 
+    @NonNull
     @Override
-    public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
+    public Presenter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent) {
         View view = onCreateView(parent);
         ViewHolder vh = new ViewHolder(view);
         ViewGroup.LayoutParams lp = view.getLayoutParams();
@@ -106,9 +114,9 @@
      * @param parentViewHolder
      * @param parentPresenter
      */
-    public void setContext(ViewHolder viewHolder,
-            FullWidthDetailsOverviewRowPresenter.ViewHolder parentViewHolder,
-            FullWidthDetailsOverviewRowPresenter parentPresenter) {
+    public void setContext(@NonNull ViewHolder viewHolder,
+            @Nullable FullWidthDetailsOverviewRowPresenter.ViewHolder parentViewHolder,
+            @Nullable FullWidthDetailsOverviewRowPresenter parentPresenter) {
         viewHolder.mParentViewHolder = parentViewHolder;
         viewHolder.mParentPresenter = parentPresenter;
     }
@@ -121,7 +129,10 @@
      * {@link FullWidthDetailsOverviewRowPresenter#notifyOnBindLogo(FullWidthDetailsOverviewRowPresenter.ViewHolder)}
      * when image view is bound to the drawable.
      */
-    public boolean isBoundToImage(ViewHolder viewHolder, DetailsOverviewRow row) {
+    public boolean isBoundToImage(
+            @NonNull ViewHolder viewHolder,
+            @Nullable DetailsOverviewRow row
+    ) {
         return row != null && row.getImageDrawable() != null;
     }
 
@@ -133,7 +144,7 @@
      * @param item DetailsOverviewRow object to bind.
      */
     @Override
-    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
+    public void onBindViewHolder(@NonNull Presenter.ViewHolder viewHolder, @NonNull Object item) {
         DetailsOverviewRow row = (DetailsOverviewRow) item;
         ImageView imageView = ((ImageView) viewHolder.view);
         imageView.setImageDrawable(row.getImageDrawable());
@@ -167,7 +178,7 @@
     }
 
     @Override
-    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
+    public void onUnbindViewHolder(@NonNull Presenter.ViewHolder viewHolder) {
     }
 
 }
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/GuidedAction.java b/leanback/leanback/src/main/java/androidx/leanback/widget/GuidedAction.java
index c2857b2..bb05177 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/GuidedAction.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/GuidedAction.java
@@ -13,6 +13,7 @@
  */
 package androidx.leanback.widget;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
@@ -20,6 +21,8 @@
 import android.text.InputType;
 
 import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 import androidx.core.content.ContextCompat;
 import androidx.leanback.R;
@@ -142,7 +145,7 @@
          * Creates a BuilderBase for GuidedAction or its subclass.
          * @param context Context object used to build the GuidedAction.
          */
-        public BuilderBase(Context context) {
+        public BuilderBase(@NonNull Context context) {
             mContext = context;
             mActionFlags = PF_ENABLED | PF_FOCUSABLE | PF_AUTORESTORE;
         }
@@ -151,6 +154,7 @@
          * Returns Context of this Builder.
          * @return Context of this Builder.
          */
+        @NonNull
         public Context getContext() {
             return mContext;
         }
@@ -163,7 +167,7 @@
          * Subclass of BuilderBase should call this function to apply values.
          * @param action GuidedAction to apply BuilderBase values.
          */
-        protected final void applyValues(GuidedAction action) {
+        protected final void applyValues(@NonNull GuidedAction action) {
             // Base Action values
             action.setId(mId);
             action.setLabel1(mTitle);
@@ -231,7 +235,7 @@
          * action to be taken on click, e.g. "Continue" or "Cancel".
          * @param title The title for this action.
          */
-        public B title(CharSequence title) {
+        public B title(@Nullable CharSequence title) {
             mTitle = title;
             return (B) this;
         }
@@ -251,7 +255,7 @@
          * replaces the string of title.
          * @param editTitle The optional title text to edit when TextView is activated.
          */
-        public B editTitle(CharSequence editTitle) {
+        public B editTitle(@Nullable CharSequence editTitle) {
             mEditTitle = editTitle;
             return (B) this;
         }
@@ -272,7 +276,7 @@
          * providing extra information on what the action will do.
          * @param description The description for this action.
          */
-        public B description(CharSequence description) {
+        public B description(@Nullable CharSequence description) {
             mDescription = description;
             return (B) this;
         }
@@ -292,7 +296,7 @@
          * description replaces the string of description.
          * @param description The description to edit for this action.
          */
-        public B editDescription(CharSequence description) {
+        public B editDescription(@Nullable CharSequence description) {
             mEditDescription = description;
             return (B) this;
         }
@@ -313,7 +317,7 @@
          * directly when the action is clicked.
          * @param intent The intent associated with this action.
          */
-        public B intent(Intent intent) {
+        public B intent(@Nullable Intent intent) {
             mIntent = intent;
             return (B) this;
         }
@@ -322,7 +326,7 @@
          * Sets the action's icon drawable.
          * @param icon The drawable for the icon associated with this action.
          */
-        public B icon(Drawable icon) {
+        public B icon(@Nullable Drawable icon) {
             mIcon = icon;
             return (B) this;
         }
@@ -530,7 +534,7 @@
          * @param subActions
          * @return The same BuilderBase object.
          */
-        public B subActions(List<GuidedAction> subActions) {
+        public B subActions(@Nullable List<GuidedAction> subActions) {
             mSubActions = subActions;
             return (B) this;
         }
@@ -552,7 +556,7 @@
          * @param hints List of hints for autofill.
          * @return The same BuilderBase object.
          */
-        public B autofillHints(String... hints) {
+        public B autofillHints(@Nullable String... hints) {
             mAutofillHints = hints;
             return (B) this;
         }
@@ -575,7 +579,7 @@
          * Creates a Builder for GuidedAction.
          * @param context Context to build GuidedAction.
          */
-        public Builder(Context context) {
+        public Builder(@Nullable Context context) {
             super(context);
         }
 
@@ -583,6 +587,7 @@
          * Builds the GuidedAction corresponding to this Builder.
          * @return The GuidedAction as configured through this Builder.
          */
+        @NonNull
         public GuidedAction build() {
             GuidedAction action = new GuidedAction();
             applyValues(action);
@@ -627,6 +632,7 @@
      * Returns the title of this action.
      * @return The title set when this action was built.
      */
+    @Nullable
     public CharSequence getTitle() {
         return getLabel1();
     }
@@ -635,7 +641,7 @@
      * Sets the title of this action.
      * @param title The title set when this action was built.
      */
-    public void setTitle(CharSequence title) {
+    public void setTitle(@Nullable CharSequence title) {
         setLabel1(title);
     }
 
@@ -644,6 +650,7 @@
      * {@link #getTitle()}.
      * @return Optional title text to edit instead of {@link #getTitle()}.
      */
+    @Nullable
     public CharSequence getEditTitle() {
         return mEditTitle;
     }
@@ -652,7 +659,7 @@
      * Sets the optional title text to edit instead of {@link #setTitle(CharSequence)}.
      * @param editTitle Optional title text to edit instead of {@link #setTitle(CharSequence)}.
      */
-    public void setEditTitle(CharSequence editTitle) {
+    public void setEditTitle(@Nullable CharSequence editTitle) {
         mEditTitle = editTitle;
     }
 
@@ -661,6 +668,7 @@
      * {@link #getDescription()}.
      * @return Optional description text to edit instead of {@link #getDescription()}.
      */
+    @Nullable
     public CharSequence getEditDescription() {
         return mEditDescription;
     }
@@ -670,7 +678,7 @@
      * @param editDescription Optional description text to edit instead of
      * {@link #setDescription(CharSequence)}.
      */
-    public void setEditDescription(CharSequence editDescription) {
+    public void setEditDescription(@Nullable CharSequence editDescription) {
         mEditDescription = editDescription;
     }
 
@@ -687,6 +695,7 @@
      * Returns the description of this action.
      * @return The description of this action.
      */
+    @Nullable
     public CharSequence getDescription() {
         return getLabel2();
     }
@@ -695,7 +704,7 @@
      * Sets the description of this action.
      * @param description The description of the action.
      */
-    public void setDescription(CharSequence description) {
+    public void setDescription(@Nullable CharSequence description) {
         setLabel2(description);
     }
 
@@ -703,6 +712,7 @@
      * Returns the intent associated with this action.
      * @return The intent set when this action was built.
      */
+    @Nullable
     public Intent getIntent() {
         return mIntent;
     }
@@ -711,7 +721,7 @@
      * Sets the intent of this action.
      * @param intent New intent to set on this action.
      */
-    public void setIntent(Intent intent) {
+    public void setIntent(@Nullable Intent intent) {
         mIntent = intent;
     }
 
@@ -881,13 +891,15 @@
      * Change sub actions list.
      * @param actions Sub actions list to set on this action.  Sets null to disable sub actions.
      */
-    public void setSubActions(List<GuidedAction> actions) {
+    public void setSubActions(@Nullable List<GuidedAction> actions) {
         mSubActions = actions;
     }
 
     /**
      * @return List of sub actions or null if sub actions list is not enabled.
      */
+    @SuppressLint("NullableCollection")
+    @Nullable
     public List<GuidedAction> getSubActions() {
         return mSubActions;
     }
@@ -929,7 +941,7 @@
      * @param bundle  Bundle to save the Action.
      * @param key Key used to save the Action.
      */
-    public void onSaveInstanceState(Bundle bundle, String key) {
+    public void onSaveInstanceState(@NonNull Bundle bundle, @NonNull String key) {
         if (needAutoSaveTitle() && getTitle() != null) {
             bundle.putString(key, getTitle().toString());
         } else if (needAutoSaveDescription() && getDescription() != null) {
@@ -951,7 +963,7 @@
      * @param bundle  Bundle to restore the Action from.
      * @param key Key used to restore the Action.
      */
-    public void onRestoreInstanceState(Bundle bundle, String key) {
+    public void onRestoreInstanceState(@NonNull Bundle bundle, @NonNull String key) {
         if (needAutoSaveTitle()) {
             String title = bundle.getString(key);
             if (title != null) {
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/GuidedActionAdapterGroup.java b/leanback/leanback/src/main/java/androidx/leanback/widget/GuidedActionAdapterGroup.java
index f4e16be..180ea9d 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/GuidedActionAdapterGroup.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/GuidedActionAdapterGroup.java
@@ -22,6 +22,8 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.leanback.widget.GuidedActionAdapter.EditListener;
 
@@ -43,7 +45,10 @@
     private boolean mImeOpened;
     private EditListener mEditListener;
 
-    public void addAdpter(GuidedActionAdapter adapter1, GuidedActionAdapter adapter2) {
+    public void addAdpter(
+            @Nullable GuidedActionAdapter adapter1,
+            @Nullable GuidedActionAdapter adapter2
+    ) {
         mAdapters.add(new Pair<GuidedActionAdapter, GuidedActionAdapter>(adapter1, adapter2));
         if (adapter1 != null) {
             adapter1.mGroup = this;
@@ -53,7 +58,8 @@
         }
     }
 
-    public GuidedActionAdapter getNextAdapter(GuidedActionAdapter adapter) {
+    @Nullable
+    public GuidedActionAdapter getNextAdapter(@NonNull GuidedActionAdapter adapter) {
         for (int i = 0; i < mAdapters.size(); i++) {
             Pair<GuidedActionAdapter, GuidedActionAdapter> pair = mAdapters.get(i);
             if (pair.first == adapter) {
@@ -63,7 +69,7 @@
         return null;
     }
 
-    public void setEditListener(EditListener listener) {
+    public void setEditListener(@Nullable EditListener listener) {
         mEditListener = listener;
     }
 
@@ -119,7 +125,10 @@
         return false;
     }
 
-    public void openIme(GuidedActionAdapter adapter, GuidedActionsStylist.ViewHolder avh) {
+    public void openIme(
+            @NonNull GuidedActionAdapter adapter,
+            @NonNull GuidedActionsStylist.ViewHolder avh
+    ) {
         adapter.getGuidedActionsStylist().setEditingMode(avh, true);
         View v = avh.getEditingView();
         if (v == null || !avh.isInEditingText()) {
@@ -138,7 +147,7 @@
         }
     }
 
-    public void closeIme(View v) {
+    public void closeIme(@NonNull View v) {
         if (mImeOpened) {
             mImeOpened = false;
             InputMethodManager mgr = (InputMethodManager)
@@ -148,7 +157,7 @@
         }
     }
 
-    public void fillAndStay(GuidedActionAdapter adapter, TextView v) {
+    public void fillAndStay(@NonNull GuidedActionAdapter adapter, @NonNull TextView v) {
         GuidedActionsStylist.ViewHolder avh = adapter.findSubChildViewHolder(v);
         updateTextIntoAction(avh, v);
         mEditListener.onGuidedActionEditCanceled(avh.getAction());
@@ -157,7 +166,7 @@
         avh.itemView.requestFocus();
     }
 
-    public void fillAndGoNext(GuidedActionAdapter adapter, TextView v) {
+    public void fillAndGoNext(@NonNull GuidedActionAdapter adapter, @NonNull TextView v) {
         boolean handled = false;
         GuidedActionsStylist.ViewHolder avh = adapter.findSubChildViewHolder(v);
         updateTextIntoAction(avh, v);
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/ListRowPresenter.java b/leanback/leanback/src/main/java/androidx/leanback/widget/ListRowPresenter.java
index bd5b6f5..4e7fd49 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/ListRowPresenter.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/ListRowPresenter.java
@@ -20,6 +20,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.leanback.R;
 import androidx.leanback.system.Settings;
 import androidx.leanback.transition.TransitionHelper;
@@ -67,7 +69,11 @@
         final int mPaddingLeft;
         final int mPaddingRight;
 
-        public ViewHolder(View rootView, HorizontalGridView gridView, ListRowPresenter p) {
+        public ViewHolder(
+                @NonNull View rootView,
+                @NonNull HorizontalGridView gridView,
+                @NonNull ListRowPresenter p
+        ) {
             super(rootView);
             mGridView = gridView;
             mListRowPresenter = p;
@@ -81,6 +87,7 @@
          * Gets ListRowPresenter that creates this ViewHolder.
          * @return ListRowPresenter that creates this ViewHolder.
          */
+        @NonNull
         public final ListRowPresenter getListRowPresenter() {
             return mListRowPresenter;
         }
@@ -89,6 +96,7 @@
          * Gets HorizontalGridView that shows a list of items.
          * @return HorizontalGridView that shows a list of items.
          */
+        @NonNull
         public final HorizontalGridView getGridView() {
             return mGridView;
         }
@@ -97,6 +105,7 @@
          * Gets ItemBridgeAdapter that creates the list of items.
          * @return ItemBridgeAdapter that creates the list of items.
          */
+        @NonNull
         public final ItemBridgeAdapter getBridgeAdapter() {
             return mItemBridgeAdapter;
         }
@@ -115,6 +124,7 @@
          * @param position Position of the item in adapter.
          * @return ViewHolder bounds to the item.
          */
+        @Nullable
         public Presenter.ViewHolder getItemViewHolder(int position) {
             ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) mGridView
                     .findViewHolderForAdapterPosition(position);
@@ -124,11 +134,13 @@
             return ibvh.getViewHolder();
         }
 
+        @Nullable
         @Override
         public Presenter.ViewHolder getSelectedItemViewHolder() {
             return getItemViewHolder(getSelectedPosition());
         }
 
+        @Nullable
         @Override
         public Object getSelectedItem() {
             ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) mGridView
@@ -191,6 +203,7 @@
          * Returns optional task to run when the item is selected, null for no task.
          * @return Optional task to run when the item is selected, null for no task.
          */
+        @Nullable
         public Presenter.ViewHolderTask getItemTask() {
             return mItemTask;
         }
@@ -199,12 +212,12 @@
          * Sets task to run when the item is selected, null for no task.
          * @param itemTask Optional task to run when the item is selected, null for no task.
          */
-        public void setItemTask(Presenter.ViewHolderTask itemTask) {
+        public void setItemTask(@Nullable ViewHolderTask itemTask) {
             mItemTask = itemTask;
         }
 
         @Override
-        public void run(Presenter.ViewHolder holder) {
+        public void run(@Nullable Presenter.ViewHolder holder) {
             if (holder instanceof ListRowPresenter.ViewHolder) {
                 HorizontalGridView gridView = ((ListRowPresenter.ViewHolder) holder).getGridView();
                 androidx.leanback.widget.ViewHolderTask task = null;
@@ -212,7 +225,7 @@
                     task = new androidx.leanback.widget.ViewHolderTask() {
                         final Presenter.ViewHolderTask itemTask = mItemTask;
                         @Override
-                        public void run(RecyclerView.ViewHolder rvh) {
+                        public void run(@NonNull RecyclerView.ViewHolder rvh) {
                             ItemBridgeAdapter.ViewHolder ibvh = (ItemBridgeAdapter.ViewHolder) rvh;
                             itemTask.run(ibvh.getViewHolder());
                         }
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/PlaybackControlsRowPresenter.java b/leanback/leanback/src/main/java/androidx/leanback/widget/PlaybackControlsRowPresenter.java
index f1cf7cb..1052f81 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/PlaybackControlsRowPresenter.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/PlaybackControlsRowPresenter.java
@@ -13,6 +13,7 @@
  */
 package androidx.leanback.widget;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.graphics.Color;
 import android.util.TypedValue;
@@ -26,6 +27,8 @@
 import android.widget.LinearLayout;
 
 import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.core.view.ViewCompat;
 import androidx.leanback.R;
 import androidx.leanback.widget.ControlBarPresenter.OnControlClickedListener;
@@ -203,7 +206,7 @@
      *
      * @param descriptionPresenter Presenter for displaying item details.
      */
-    public PlaybackControlsRowPresenter(Presenter descriptionPresenter) {
+    public PlaybackControlsRowPresenter(@Nullable Presenter descriptionPresenter) {
         setHeaderPresenter(null);
         setSelectEffectEnabled(false);
 
@@ -227,13 +230,14 @@
     /**
      * Sets the listener for {@link Action} click events.
      */
-    public void setOnActionClickedListener(OnActionClickedListener listener) {
+    public void setOnActionClickedListener(@Nullable OnActionClickedListener listener) {
         mOnActionClickedListener = listener;
     }
 
     /**
      * Returns the listener for {@link Action} click events.
      */
+    @Nullable
     public OnActionClickedListener getOnActionClickedListener() {
         return mOnActionClickedListener;
     }
@@ -285,6 +289,7 @@
     /**
      * Returns true if secondary actions are hidden.
      */
+    @SuppressLint("KotlinPropertyAccess")
     public boolean areSecondaryActionsHidden() {
         return mSecondaryActionsHidden;
     }
@@ -294,7 +299,7 @@
      * This allows the row to hug the bottom of the display when no
      * other rows are present.
      */
-    public void showBottomSpace(ViewHolder vh, boolean show) {
+    public void showBottomSpace(@NonNull ViewHolder vh, boolean show) {
         vh.mBottomSpacer.setVisibility(show ? View.VISIBLE : View.GONE);
     }
 
@@ -302,7 +307,7 @@
      * Displays the primary actions.  This will override the user having selected "more actions"
      * to display the secondary actions; see {@link #setSecondaryActionsHidden(boolean)}.
      */
-    public void showPrimaryActions(ViewHolder vh) {
+    public void showPrimaryActions(@NonNull ViewHolder vh) {
         mPlaybackControlsPresenter.showPrimaryActions(vh.mControlsVh);
         if (vh.view.hasFocus()) {
             mPlaybackControlsPresenter.resetFocus(vh.mControlsVh);
@@ -310,7 +315,7 @@
     }
 
     @Override
-    public void onReappear(RowPresenter.ViewHolder rowViewHolder) {
+    public void onReappear(@NonNull RowPresenter.ViewHolder rowViewHolder) {
         showPrimaryActions((ViewHolder) rowViewHolder);
     }
 
@@ -331,8 +336,9 @@
         return context.getResources().getColor(R.color.lb_playback_progress_color_no_theme);
     }
 
+    @NonNull
     @Override
-    protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
+    protected RowPresenter.ViewHolder createRowViewHolder(@NonNull ViewGroup parent) {
         View v = LayoutInflater.from(parent.getContext())
             .inflate(R.layout.lb_playback_controls_row, parent, false);
         ViewHolder vh = new ViewHolder(v, mDescriptionPresenter);
@@ -373,7 +379,10 @@
     }
 
     @Override
-    protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) {
+    protected void onBindRowViewHolder(
+            @NonNull RowPresenter.ViewHolder holder,
+            @NonNull Object item
+    ) {
         super.onBindRowViewHolder(holder, item);
 
         ViewHolder vh = (ViewHolder) holder;
@@ -449,7 +458,7 @@
     }
 
     @Override
-    protected void onUnbindRowViewHolder(RowPresenter.ViewHolder holder) {
+    protected void onUnbindRowViewHolder(@NonNull RowPresenter.ViewHolder holder) {
         ViewHolder vh = (ViewHolder) holder;
         PlaybackControlsRow row = (PlaybackControlsRow) vh.getRow();
 
@@ -464,7 +473,7 @@
     }
 
     @Override
-    protected void onRowViewSelected(RowPresenter.ViewHolder vh, boolean selected) {
+    protected void onRowViewSelected(@NonNull RowPresenter.ViewHolder vh, boolean selected) {
         super.onRowViewSelected(vh, selected);
         if (selected) {
             ((ViewHolder) vh).dispatchItemSelection();
@@ -472,7 +481,7 @@
     }
 
     @Override
-    protected void onRowViewAttachedToWindow(RowPresenter.ViewHolder vh) {
+    protected void onRowViewAttachedToWindow(@NonNull RowPresenter.ViewHolder vh) {
         super.onRowViewAttachedToWindow(vh);
         if (mDescriptionPresenter != null) {
             mDescriptionPresenter.onViewAttachedToWindow(
@@ -481,7 +490,7 @@
     }
 
     @Override
-    protected void onRowViewDetachedFromWindow(RowPresenter.ViewHolder vh) {
+    protected void onRowViewDetachedFromWindow(@NonNull RowPresenter.ViewHolder vh) {
         super.onRowViewDetachedFromWindow(vh);
         if (mDescriptionPresenter != null) {
             mDescriptionPresenter.onViewDetachedFromWindow(
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/PlaybackRowPresenter.java b/leanback/leanback/src/main/java/androidx/leanback/widget/PlaybackRowPresenter.java
index 2827eaa..b68a69a 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/PlaybackRowPresenter.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/PlaybackRowPresenter.java
@@ -2,6 +2,8 @@
 
 import android.view.View;
 
+import androidx.annotation.NonNull;
+
 /**
  * Subclass of {@link RowPresenter} that can define the desired behavior when the view
  * reappears. This is presently used by {@link PlaybackControlsRowPresenter} to update the UI
@@ -22,6 +24,6 @@
     /**
      * Provides hook to update the UI when the view reappears.
      */
-    public void onReappear(RowPresenter.ViewHolder rowViewHolder) {
+    public void onReappear(@NonNull RowPresenter.ViewHolder rowViewHolder) {
     }
 }
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/Presenter.java b/leanback/leanback/src/main/java/androidx/leanback/widget/Presenter.java
index 949faa0..7e6d731 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/Presenter.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/Presenter.java
@@ -16,6 +16,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.NonNull;
 import androidx.collection.ArrayMap;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -121,12 +122,13 @@
     /**
      * Creates a new {@link View}.
      */
-    public abstract ViewHolder onCreateViewHolder(ViewGroup parent);
+    @NonNull
+    public abstract ViewHolder onCreateViewHolder(@NonNull ViewGroup parent);
 
     /**
      * Binds a {@link View} to an item.
      */
-    public abstract void onBindViewHolder(ViewHolder viewHolder, Object item);
+    public abstract void onBindViewHolder(@NonNull ViewHolder viewHolder, @NonNull Object item);
 
     /**
      * Binds a {@link View} to an item with a list of payloads.
@@ -136,7 +138,11 @@
      * @param payloads    A non-null list of merged payloads. Can be empty list if requires full
      *                    update.
      */
-    public void onBindViewHolder(ViewHolder viewHolder, Object item, List<Object> payloads) {
+    public void onBindViewHolder(
+            @NonNull ViewHolder viewHolder,
+            @NonNull Object item,
+            @NonNull List<Object> payloads
+    ) {
         onBindViewHolder(viewHolder, item);
     }
 
@@ -145,7 +151,7 @@
      * released here, and any fields that are not bound for every item should be
      * cleared here.
      */
-    public abstract void onUnbindViewHolder(ViewHolder viewHolder);
+    public abstract void onUnbindViewHolder(@NonNull ViewHolder viewHolder);
 
     /**
      * Called when a view created by this presenter has been attached to a window.
@@ -157,7 +163,7 @@
      *
      * @param holder Holder of the view being attached
      */
-    public void onViewAttachedToWindow(ViewHolder holder) {
+    public void onViewAttachedToWindow(@NonNull ViewHolder holder) {
     }
 
     /**
@@ -172,7 +178,7 @@
      *
      * @param holder Holder of the view being detached
      */
-    public void onViewDetachedFromWindow(ViewHolder holder) {
+    public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
         // If there are view property animations running then RecyclerView won't recycle.
         cancelAnimationsRecursive(holder.view);
     }
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/RowPresenter.java b/leanback/leanback/src/main/java/androidx/leanback/widget/RowPresenter.java
index 6433695..cce3c17 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/RowPresenter.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/RowPresenter.java
@@ -16,6 +16,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.leanback.app.HeadersFragment;
 import androidx.leanback.graphics.ColorOverlayDimmer;
 
@@ -295,6 +297,7 @@
          * Return {@link ViewHolder} of currently selected item inside a row ViewHolder.
          * @return The selected item's ViewHolder.
          */
+        @Nullable
         public Presenter.ViewHolder getSelectedItemViewHolder() {
             return null;
         }
@@ -303,6 +306,7 @@
          * Return currently selected item inside a row ViewHolder.
          * @return The selected item.
          */
+        @Nullable
         public Object getSelectedItem() {
             return null;
         }
@@ -350,7 +354,8 @@
      * @param parent The parent View for the Row's view holder.
      * @return A ViewHolder for the Row's View.
      */
-    protected abstract ViewHolder createRowViewHolder(ViewGroup parent);
+    @NonNull
+    protected abstract ViewHolder createRowViewHolder(@NonNull ViewGroup parent);
 
     /**
      * Returns true if the Row view should clip its children.  The clipChildren
@@ -512,7 +517,7 @@
      * respond to selected state changes of a Row.  A subclass may make visual changes to Row view
      * but must not create animation on the Row view.
      */
-    protected void onRowViewSelected(ViewHolder vh, boolean selected) {
+    protected void onRowViewSelected(@NonNull ViewHolder vh, boolean selected) {
         dispatchItemSelectedListener(vh, selected);
         updateHeaderViewVisibility(vh);
         updateActivateStatus(vh, vh.view);
@@ -611,7 +616,7 @@
      * {@link #onBindRowViewHolder(ViewHolder, Object)} must call through the super class's
      * implementation of this method.
      */
-    protected void onBindRowViewHolder(ViewHolder vh, Object item) {
+    protected void onBindRowViewHolder(@NonNull ViewHolder vh, @NonNull Object item) {
         vh.mRowObject = item;
         vh.mRow = item instanceof Row ? (Row) item : null;
         if (vh.mHeaderViewHolder != null && vh.getRow() != null) {
@@ -629,7 +634,7 @@
      * Derived classes of {@link RowPresenter} overriding {@link #onUnbindRowViewHolder(ViewHolder)}
      * must call through the super class's implementation of this method.
      */
-    protected void onUnbindRowViewHolder(ViewHolder vh) {
+    protected void onUnbindRowViewHolder(@NonNull ViewHolder vh) {
         if (vh.mHeaderViewHolder != null) {
             mHeaderPresenter.onUnbindViewHolder(vh.mHeaderViewHolder);
         }
@@ -645,7 +650,7 @@
     /**
      * Invoked when the row view is attached to the window.
      */
-    protected void onRowViewAttachedToWindow(ViewHolder vh) {
+    protected void onRowViewAttachedToWindow(@NonNull ViewHolder vh) {
         if (vh.mHeaderViewHolder != null) {
             mHeaderPresenter.onViewAttachedToWindow(vh.mHeaderViewHolder);
         }
@@ -659,7 +664,7 @@
     /**
      * Invoked when the row view is detached from the window.
      */
-    protected void onRowViewDetachedFromWindow(ViewHolder vh) {
+    protected void onRowViewDetachedFromWindow(@NonNull ViewHolder vh) {
         if (vh.mHeaderViewHolder != null) {
             mHeaderPresenter.onViewDetachedFromWindow(vh.mHeaderViewHolder);
         }
@@ -683,7 +688,7 @@
      * @param afterEntrance  true if children of row participating in entrance transition
      *                       should be set to visible, false otherwise.
      */
-    public void setEntranceTransitionState(ViewHolder holder, boolean afterEntrance) {
+    public void setEntranceTransitionState(@NonNull ViewHolder holder, boolean afterEntrance) {
         if (holder.mHeaderViewHolder != null
                 && holder.mHeaderViewHolder.view.getVisibility() != View.GONE) {
             holder.mHeaderViewHolder.view.setVisibility(afterEntrance
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/SearchOrbView.java b/leanback/leanback/src/main/java/androidx/leanback/widget/SearchOrbView.java
index 5870c24..870bbf5 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/SearchOrbView.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/SearchOrbView.java
@@ -33,6 +33,8 @@
 import android.widget.ImageView;
 
 import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.core.view.ViewCompat;
 import androidx.leanback.R;
 
@@ -145,16 +147,16 @@
         ViewCompat.setZ(mSearchOrbView, mUnfocusedZ + fraction * (mFocusedZ - mUnfocusedZ));
     }
 
-    public SearchOrbView(Context context) {
+    public SearchOrbView(@NonNull Context context) {
         this(context, null);
     }
 
-    public SearchOrbView(Context context, AttributeSet attrs) {
+    public SearchOrbView(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, R.attr.searchOrbViewStyle);
     }
 
     @SuppressLint("CustomViewStyleable")
-    public SearchOrbView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public SearchOrbView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
         final Resources res = context.getResources();
@@ -240,7 +242,11 @@
     }
 
     @Override
-    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+    protected void onFocusChanged(
+            boolean gainFocus,
+            int direction,
+            @Nullable Rect previouslyFocusedRect
+    ) {
         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
         animateOnFocus(gainFocus);
     }
@@ -257,7 +263,7 @@
      *
      * @param icon the drawable to be used as the icon
      */
-    public void setOrbIcon(Drawable icon) {
+    public void setOrbIcon(@NonNull Drawable icon) {
         mIconDrawable = icon;
         mIcon.setImageDrawable(mIconDrawable);
     }
@@ -267,6 +273,7 @@
      *
      * @return the drawable used as the icon
      */
+    @Nullable
     public Drawable getOrbIcon() {
         return mIconDrawable;
     }
@@ -276,7 +283,7 @@
      *
      * @param listener The listener.
      */
-    public void setOnOrbClickedListener(OnClickListener listener) {
+    public void setOnOrbClickedListener(@Nullable OnClickListener listener) {
         mListener = listener;
     }
 
@@ -314,7 +321,7 @@
     /**
      * Sets the {@link Colors} used to display the search orb.
      */
-    public void setOrbColors(Colors colors) {
+    public void setOrbColors(@NonNull Colors colors) {
         mColors = colors;
         mIcon.setColorFilter(mColors.iconColor);
 
@@ -328,6 +335,7 @@
     /**
      * Returns the {@link Colors} used to display the search orb.
      */
+    @Nullable
     public Colors getOrbColors() {
         return mColors;
     }
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/TitleView.java b/leanback/leanback/src/main/java/androidx/leanback/widget/TitleView.java
index 05eaa9a..f96033f 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/TitleView.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/TitleView.java
@@ -26,6 +26,8 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.leanback.R;
 
 /**
@@ -91,15 +93,15 @@
         }
     };
 
-    public TitleView(Context context) {
+    public TitleView(@NonNull Context context) {
         this(context, null);
     }
 
-    public TitleView(Context context, AttributeSet attrs) {
+    public TitleView(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, R.attr.browseTitleViewStyle);
     }
 
-    public TitleView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public TitleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
         LayoutInflater inflater = LayoutInflater.from(context);
@@ -116,7 +118,7 @@
     /**
      * Sets the title text.
      */
-    public void setTitle(CharSequence titleText) {
+    public void setTitle(@Nullable CharSequence titleText) {
         mTextView.setText(titleText);
         updateBadgeVisibility();
     }
@@ -124,6 +126,7 @@
     /**
      * Returns the title text.
      */
+    @Nullable
     public CharSequence getTitle() {
         return mTextView.getText();
     }
@@ -132,7 +135,7 @@
      * Sets the badge drawable.
      * If non-null, the drawable is displayed instead of the title text.
      */
-    public void setBadgeDrawable(Drawable drawable) {
+    public void setBadgeDrawable(@Nullable Drawable drawable) {
         mBadgeView.setImageDrawable(drawable);
         updateBadgeVisibility();
     }
@@ -140,6 +143,7 @@
     /**
      * Returns the badge drawable.
      */
+    @Nullable
     public Drawable getBadgeDrawable() {
         return mBadgeView.getDrawable();
     }
@@ -147,7 +151,7 @@
     /**
      * Sets the listener to be called when the search affordance is clicked.
      */
-    public void setOnSearchClickedListener(View.OnClickListener listener) {
+    public void setOnSearchClickedListener(@Nullable OnClickListener listener) {
         mHasSearchListener = listener != null;
         mSearchOrbView.setOnOrbClickedListener(listener);
         updateSearchOrbViewVisiblity();
@@ -156,6 +160,7 @@
     /**
      *  Returns the view for the search affordance.
      */
+    @NonNull
     public View getSearchAffordanceView() {
         return mSearchOrbView;
     }
@@ -163,13 +168,14 @@
     /**
      * Sets the {@link SearchOrbView.Colors} used to draw the search affordance.
      */
-    public void setSearchAffordanceColors(SearchOrbView.Colors colors) {
+    public void setSearchAffordanceColors(@NonNull SearchOrbView.Colors colors) {
         mSearchOrbView.setOrbColors(colors);
     }
 
     /**
      * Returns the {@link SearchOrbView.Colors} used to draw the search affordance.
      */
+    @Nullable
     public SearchOrbView.Colors getSearchAffordanceColors() {
         return mSearchOrbView.getOrbColors();
     }
@@ -220,6 +226,7 @@
     }
 
     @Override
+    @NonNull
     public TitleViewAdapter getTitleViewAdapter() {
         return mTitleViewAdapter;
     }
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java b/leanback/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java
index f037729..8f6d9c2 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java
@@ -31,6 +31,8 @@
 
 import androidx.annotation.IdRes;
 import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.core.view.ViewCompat;
 import androidx.leanback.R;
 import androidx.leanback.widget.OnChildViewHolderSelectedListener;
@@ -73,7 +75,7 @@
          * @param picker View whose value has changed.
          * @param column Column whose value has changed.
          */
-        void onValueChanged(Picker picker, int column);
+        void onValueChanged(@NonNull Picker picker, int column);
     }
 
     private ViewGroup mPickerView;
@@ -111,7 +113,7 @@
      *
      * @param separator Separator String between Picker columns.
      */
-    public final void setSeparator(CharSequence separator) {
+    public final void setSeparator(@NonNull CharSequence separator) {
         setSeparators(Arrays.asList(separator));
     }
 
@@ -120,6 +122,7 @@
      *
      * @return The list of separators populated between the picker column fields.
      */
+    @NonNull
     public final List<CharSequence> getSeparators() {
         return mSeparators;
     }
@@ -136,7 +139,7 @@
      *
      * @param separators The list of separators to be populated between the Picker columns.
      */
-    public final void setSeparators(List<CharSequence> separators) {
+    public final void setSeparators(@NonNull List<CharSequence> separators) {
         mSeparators.clear();
         mSeparators.addAll(separators);
     }
@@ -186,15 +189,15 @@
     /**
      * Creates a Picker widget.
      */
-    public Picker(Context context, AttributeSet attributeSet) {
+    public Picker(@NonNull Context context, @Nullable AttributeSet attributeSet) {
         this(context, attributeSet, R.attr.pickerStyle);
     }
 
     /**
      * Creates a Picker widget.
-     */
+      */
     @SuppressLint("CustomViewStyleable")
-    public Picker(Context context, AttributeSet attrs, int defStyleAttr) {
+    public Picker(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.lbPicker, defStyleAttr, 0);
@@ -229,6 +232,7 @@
      * @param colIndex Index of PickerColumn.
      * @return PickerColumn at colIndex or null if {@link #setColumns(List)} is not called yet.
      */
+    @Nullable
     public PickerColumn getColumnAt(int colIndex) {
         if (mColumns == null) {
             return null;
@@ -255,7 +259,7 @@
      *                takes more than one value (e.g. for a DatePicker, day, month, and year fields
      *                and for TimePicker, hour, minute, and am/pm fields form the columns).
      */
-    public void setColumns(List<PickerColumn> columns) {
+    public void setColumns(@NonNull List<PickerColumn> columns) {
         if (mSeparators.size() == 0) {
             throw new IllegalStateException("Separators size is: " + mSeparators.size()
                     + ". At least one separator must be provided");
@@ -330,7 +334,7 @@
      * @param columnIndex Index of column to update.
      * @param column      New column to update.
      */
-    public void setColumnAt(int columnIndex, PickerColumn column) {
+    public void setColumnAt(int columnIndex, @NonNull PickerColumn column) {
         mColumns.set(columnIndex, column);
         VerticalGridView columnView = mColumnViews.get(columnIndex);
         PickerScrollArrayAdapter adapter = (PickerScrollArrayAdapter) columnView.getAdapter();
@@ -377,7 +381,7 @@
      *
      * @param listener The callback to ad
      */
-    public void addOnValueChangedListener(PickerValueListener listener) {
+    public void addOnValueChangedListener(@NonNull PickerValueListener listener) {
         if (mListeners == null) {
             mListeners = new ArrayList<>();
         }
@@ -389,7 +393,7 @@
      *
      * @param listener The callback to remove.
      */
-    public void removeOnValueChangedListener(PickerValueListener listener) {
+    public void removeOnValueChangedListener(@NonNull PickerValueListener listener) {
         if (mListeners != null) {
             mListeners.remove(listener);
         }
diff --git a/libraryversions.toml b/libraryversions.toml
index b930937..f81a131 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -19,7 +19,7 @@
 CAR_APP = "1.3.0-alpha01"
 COLLECTION = "1.3.0-alpha01"
 COMPOSE = "1.3.0-alpha01"
-COMPOSE_COMPILER = "1.2.0"
+COMPOSE_COMPILER = "1.3.0-beta01"
 COMPOSE_MATERIAL3 = "1.0.0-alpha14"
 COMPOSE_RUNTIME_TRACING = "1.0.0-alpha01"
 CONTENTPAGER = "1.1.0-alpha01"
@@ -83,7 +83,7 @@
 PRINT = "1.1.0-beta01"
 PROFILEINSTALLER = "1.3.0-alpha01"
 RECOMMENDATION = "1.1.0-alpha01"
-RECYCLERVIEW = "1.3.0-alpha03"
+RECYCLERVIEW = "1.3.0-beta01"
 RECYCLERVIEW_SELECTION = "1.2.0-alpha02"
 REMOTECALLBACK = "1.0.0-alpha02"
 RESOURCEINSPECTION = "1.1.0-alpha01"
@@ -138,7 +138,7 @@
 ACTIVITY = { group = "androidx.activity", atomicGroupVersion = "versions.ACTIVITY" }
 ADS = { group = "androidx.ads" }
 ANNOTATION = { group = "androidx.annotation" }
-APPCOMPAT = { group = "androidx.appcompat" }
+APPCOMPAT = { group = "androidx.appcompat", atomicGroupVersion = "versions.APPCOMPAT" }
 APPSEARCH = { group = "androidx.appsearch", atomicGroupVersion = "versions.APPSEARCH" }
 ARCH_CORE = { group = "androidx.arch.core", atomicGroupVersion = "versions.ARCH_CORE" }
 ASYNCLAYOUTINFLATER = { group = "androidx.asynclayoutinflater", atomicGroupVersion = "versions.ASYNCLAYOUTINFLATER" }
diff --git a/lifecycle/integration-tests/testapp/build.gradle b/lifecycle/integration-tests/testapp/build.gradle
index e20cd13..c1e3d0a 100644
--- a/lifecycle/integration-tests/testapp/build.gradle
+++ b/lifecycle/integration-tests/testapp/build.gradle
@@ -37,6 +37,7 @@
     androidTestImplementation(libs.testRunner)
     androidTestImplementation(libs.testRules)
     androidTestImplementation(libs.espressoCore)
+    androidTestImplementation(libs.truth)
 
     testImplementation(libs.junit)
     testImplementation(libs.mockitoCore)
diff --git a/lifecycle/integration-tests/testapp/src/androidTest/java/androidx/lifecycle/PartiallyCoveredActivityTest.java b/lifecycle/integration-tests/testapp/src/androidTest/java/androidx/lifecycle/PartiallyCoveredActivityTest.java
index 9c1aa32..31c9597 100644
--- a/lifecycle/integration-tests/testapp/src/androidTest/java/androidx/lifecycle/PartiallyCoveredActivityTest.java
+++ b/lifecycle/integration-tests/testapp/src/androidTest/java/androidx/lifecycle/PartiallyCoveredActivityTest.java
@@ -29,8 +29,8 @@
 import static androidx.lifecycle.testapp.TestEvent.LIFECYCLE_EVENT;
 import static androidx.lifecycle.testapp.TestEvent.OWNER_CALLBACK;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
@@ -46,7 +46,6 @@
 import androidx.lifecycle.testapp.NavigationDialogActivity;
 import androidx.lifecycle.testapp.TestEvent;
 import androidx.test.core.app.ApplicationProvider;
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
 import androidx.test.filters.SdkSuppress;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -58,7 +57,6 @@
 import org.junit.runners.Parameterized;
 
 import java.util.List;
-import java.util.concurrent.ExecutionException;
 
 import kotlin.Pair;
 
@@ -127,7 +125,6 @@
         runTest(activity);
     }
 
-    @FlakyTest(bugId = 206645367)
     @Test
     public void coveredWithDialog_fragment() throws Throwable {
         CollectingSupportFragment fragment = new CollectingSupportFragment();
@@ -151,12 +148,12 @@
         FragmentActivity dialog = launchDialog();
         assertStateSaving();
         waitForIdle();
-        assertThat(owner.copyCollectedEvents(), is(EXPECTED[0]));
+        assertThat(owner.copyCollectedEvents()).isEqualTo(EXPECTED[0]);
         List<Pair<TestEvent, Lifecycle.Event>> expected;
         if (mDismissDialog) {
             dialog.finish();
             TestUtils.waitTillResumed(activityRule.getActivity(), activityRule);
-            assertThat(owner.copyCollectedEvents(), is(flatMap(EXPECTED[0], EXPECTED[1])));
+            assertThat(owner.copyCollectedEvents()).isEqualTo(flatMap(EXPECTED[0], EXPECTED[1]));
             expected = flatMap(EXPECTED[0], EXPECTED[1], EXPECTED[2]);
         } else {
             expected = flatMap(CREATE, START, RESUME, PAUSE, STOP, DESTROY);
@@ -164,22 +161,22 @@
         CollectingSupportActivity activity = activityRule.getActivity();
         activityRule.finishActivity();
         TestUtils.waitTillDestroyed(activity, activityRule);
-        assertThat(owner.copyCollectedEvents(), is(expected));
+        assertThat(owner.copyCollectedEvents()).isEqualTo(expected);
     }
 
     // test sanity
-    private void assertStateSaving() throws ExecutionException, InterruptedException {
+    private void assertStateSaving() throws InterruptedException {
         final CollectingSupportActivity activity = activityRule.getActivity();
         if (sShouldSave) {
             // state should be saved. wait for it to be saved
-            assertThat("test sanity",
-                    activity.waitForStateSave(20), is(true));
-            assertThat("test sanity", activity.getSupportFragmentManager()
-                    .isStateSaved(), is(true));
+            assertWithMessage("activity failed to call saveInstanceState")
+                    .that(activity.waitForStateSave(20)).isTrue();
+            assertWithMessage("the state should have been saved")
+                    .that(activity.getSupportFragmentManager().isStateSaved()).isTrue();
         } else {
             // should should not be saved
-            assertThat("test sanity", activity.getSupportFragmentManager()
-                    .isStateSaved(), is(false));
+            assertWithMessage("the state should not be saved")
+                    .that(activity.getSupportFragmentManager().isStateSaved()).isFalse();
         }
     }
 
diff --git a/lifecycle/lifecycle-common/lint-baseline.xml b/lifecycle/lifecycle-common/lint-baseline.xml
deleted file mode 100644
index 3fd3fa1..0000000
--- a/lifecycle/lifecycle-common/lint-baseline.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="BanUncheckedReflection"
-        message="Calling `Method.invoke` without an SDK check"
-        errorLine1="                        mMethod.invoke(target);"
-        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/ClassesInfoCache.java"/>
-    </issue>
-
-    <issue
-        id="BanUncheckedReflection"
-        message="Calling `Method.invoke` without an SDK check"
-        errorLine1="                        mMethod.invoke(target, source);"
-        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/ClassesInfoCache.java"/>
-    </issue>
-
-    <issue
-        id="BanUncheckedReflection"
-        message="Calling `Method.invoke` without an SDK check"
-        errorLine1="                        mMethod.invoke(target, source, event);"
-        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/ClassesInfoCache.java"/>
-    </issue>
-
-    <issue
-        id="LambdaLast"
-        message="Functional interface parameters (such as parameter 1, &quot;source&quot;, in androidx.lifecycle.GeneratedAdapter.callMethods) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
-        errorLine1="            MethodCallsLogger logger);"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/GeneratedAdapter.java"/>
-    </issue>
-
-    <issue
-        id="LambdaLast"
-        message="Functional interface parameters (such as parameter 1, &quot;source&quot;, in androidx.lifecycle.LifecycleEventObserver.onStateChanged) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
-        errorLine1="    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);"
-        errorLine2="                                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/LifecycleEventObserver.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void callMethods(LifecycleOwner source, Lifecycle.Event event, boolean onAny,"
-        errorLine2="                     ~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/GeneratedAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    void callMethods(LifecycleOwner source, Lifecycle.Event event, boolean onAny,"
-        errorLine2="                                            ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/GeneratedAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            MethodCallsLogger logger);"
-        errorLine2="            ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/GeneratedAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static String getAdapterName(String className) {"
-        errorLine2="                  ~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/Lifecycling.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static String getAdapterName(String className) {"
-        errorLine2="                                        ~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/Lifecycling.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public boolean approveCall(String name, int type) {"
-        errorLine2="                               ~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/MethodCallsLogger.java"/>
-    </issue>
-
-</issues>
diff --git a/lifecycle/lifecycle-extensions/lint-baseline.xml b/lifecycle/lifecycle-extensions/lint-baseline.xml
index 66028fd..454300f 100644
--- a/lifecycle/lifecycle-extensions/lint-baseline.xml
+++ b/lifecycle/lifecycle-extensions/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="PrivateConstructorForUtilityClass"
diff --git a/lifecycle/lifecycle-reactivestreams/lint-baseline.xml b/lifecycle/lifecycle-reactivestreams/lint-baseline.xml
deleted file mode 100644
index ff4e6d2..0000000
--- a/lifecycle/lifecycle-reactivestreams/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="LambdaLast"
-        message="Functional interface parameters (such as parameter 1, &quot;lifecycle&quot;, in androidx.lifecycle.LiveDataReactiveStreams.toPublisher) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
-        errorLine1="            @NonNull LifecycleOwner lifecycle, @NonNull LiveData&lt;T> liveData) {"
-        errorLine2="                                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/lifecycle/LiveDataReactiveStreams.java"/>
-    </issue>
-
-</issues>
diff --git a/lifecycle/lifecycle-runtime-compose/integration-tests/lifecycle-runtime-compose-demos/src/main/AndroidManifest.xml b/lifecycle/lifecycle-runtime-compose/integration-tests/lifecycle-runtime-compose-demos/src/main/AndroidManifest.xml
deleted file mode 100644
index fce8bf8..0000000
--- a/lifecycle/lifecycle-runtime-compose/integration-tests/lifecycle-runtime-compose-demos/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<!--
-  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.
-  -->
-
-<manifest package="androidx.lifecycle.runtime.compose.demos" />
diff --git a/lifecycle/lifecycle-runtime-compose/samples/src/main/AndroidManifest.xml b/lifecycle/lifecycle-runtime-compose/samples/src/main/AndroidManifest.xml
deleted file mode 100644
index edbc6cf..0000000
--- a/lifecycle/lifecycle-runtime-compose/samples/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<!--
-  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.
-  -->
-
-<manifest package="androidx.lifecycle.runtime.compose.samples" />
diff --git a/lifecycle/lifecycle-runtime-compose/src/androidTest/AndroidManifest.xml b/lifecycle/lifecycle-runtime-compose/src/androidTest/AndroidManifest.xml
deleted file mode 100644
index f77804a..0000000
--- a/lifecycle/lifecycle-runtime-compose/src/androidTest/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  -->
-<manifest package="androidx.lifecycle.runtime.compose" />
diff --git a/lifecycle/lifecycle-runtime-compose/src/main/AndroidManifest.xml b/lifecycle/lifecycle-runtime-compose/src/main/AndroidManifest.xml
deleted file mode 100644
index f77804a..0000000
--- a/lifecycle/lifecycle-runtime-compose/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  -->
-<manifest package="androidx.lifecycle.runtime.compose" />
diff --git a/lifecycle/lifecycle-runtime/.gitignore b/lifecycle/lifecycle-runtime/.gitignore
deleted file mode 100644
index 796b96d..0000000
--- a/lifecycle/lifecycle-runtime/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
diff --git a/lifecycle/lifecycle-runtime/src/main/AndroidManifest.xml b/lifecycle/lifecycle-runtime/src/main/AndroidManifest.xml
deleted file mode 100644
index 9752998..0000000
--- a/lifecycle/lifecycle-runtime/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 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.
-  -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android">
-</manifest>
diff --git a/lint-checks/lint-baseline.xml b/lint-checks/lint-baseline.xml
deleted file mode 100644
index 6c29641..0000000
--- a/lint-checks/lint-baseline.xml
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="BanConcurrentHashMap"
-        message="Detected ConcurrentHashMap usage."
-        errorLine1="import java.util.concurrent.ConcurrentHashMap;"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="integration-tests/src/main/java/androidx/ConcurrentHashMapUsageJava.java"/>
-    </issue>
-
-    <issue
-        id="BanConcurrentHashMap"
-        message="Detected ConcurrentHashMap usage."
-        errorLine1="import java.util.concurrent.ConcurrentHashMap"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="integration-tests/src/main/java/androidx/ConcurrentHashMapUsageKotlin.kt"/>
-    </issue>
-
-    <issue
-        id="BanConcurrentHashMap"
-        message="Detected ConcurrentHashMap usage."
-        errorLine1="import java.util.concurrent.ConcurrentHashMap;"
-        errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="integration-tests/src/main/java/androidx/Sample.java"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    public synchronized void someMethod() {"
-        errorLine2="    ^">
-        <location
-            file="integration-tests/src/main/java/androidx/SynchronizedMethodJava.java"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    @Synchronized"
-        errorLine2="    ^">
-        <location
-            file="integration-tests/src/main/java/androidx/SynchronizedMethodKotlin.kt"/>
-    </issue>
-
-    <issue
-        id="IdeaSuppression"
-        message="Uses IntelliJ-specific suppression, should use `@SuppressWarnings(&quot;deprecation&quot;)`"
-        errorLine1="        //noinspection deprecation"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="integration-tests/src/main/java/androidx/IdeaSuppressionJava.java"/>
-    </issue>
-
-    <issue
-        id="IdeaSuppression"
-        message="Uses IntelliJ-specific suppression, should use `@SuppressWarnings(&quot;deprecation&quot;)`"
-        errorLine1="        //noinspection deprecation"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="integration-tests/src/main/java/androidx/IdeaSuppressionKotlin.kt"/>
-    </issue>
-
-    <issue
-        id="PrivateConstructorForUtilityClass"
-        message="Utility class is missing private constructor"
-        errorLine1="    static class DefaultInnerClass {"
-        errorLine2="                 ~~~~~~~~~~~~~~~~~">
-        <location
-            file="integration-tests/src/main/java/androidx/PrivateConstructorForUtilityClassJava.java"/>
-    </issue>
-
-    <issue
-        id="PrivateConstructorForUtilityClass"
-        message="Utility class is missing private constructor"
-        errorLine1="    protected static class ProtectedInnerClass {"
-        errorLine2="                           ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="integration-tests/src/main/java/androidx/PrivateConstructorForUtilityClassJava.java"/>
-    </issue>
-
-    <issue
-        id="PrivateConstructorForUtilityClass"
-        message="Utility class is missing private constructor"
-        errorLine1="    public static class PublicInnerClass {"
-        errorLine2="                        ~~~~~~~~~~~~~~~~">
-        <location
-            file="integration-tests/src/main/java/androidx/PrivateConstructorForUtilityClassJava.java"/>
-    </issue>
-
-    <issue
-        id="NullabilityAnnotationsDetector"
-        message="Use @androidx.annotation.NonNull instead of @org.jetbrains.annotations.NotNull"
-        errorLine1="    private void method1(@NotNull String arg) {"
-        errorLine2="                         ~~~~~~~~">
-        <location file="integration-tests/src/main/java/androidx/NullabilityAnnotationsJava.java"/>
-    </issue>
-
-    <issue
-        id="NullabilityAnnotationsDetector"
-        message="Use @androidx.annotation.Nullable instead of @org.jetbrains.annotations.Nullable"
-        errorLine1="    private void method2(@Nullable String arg) {"
-        errorLine2="                         ~~~~~~~~~">
-        <location file="integration-tests/src/main/java/androidx/NullabilityAnnotationsJava.java"/>
-    </issue>
-
-</issues>
diff --git a/lint-checks/src/main/java/androidx/build/lint/BanConcurrentHashMap.kt b/lint-checks/src/main/java/androidx/build/lint/BanConcurrentHashMap.kt
index b5529a3..41191a3 100644
--- a/lint-checks/src/main/java/androidx/build/lint/BanConcurrentHashMap.kt
+++ b/lint-checks/src/main/java/androidx/build/lint/BanConcurrentHashMap.kt
@@ -32,7 +32,6 @@
 import org.jetbrains.uast.UElement
 import org.jetbrains.uast.UImportStatement
 import org.jetbrains.uast.UQualifiedReferenceExpression
-import org.jetbrains.uast.USimpleNameReferenceExpression
 
 class BanConcurrentHashMap : Detector(), Detector.UastScanner {
 
@@ -44,41 +43,62 @@
     override fun createUastHandler(context: JavaContext): UElementHandler = object :
         UElementHandler() {
 
-        // Detect fully qualified reference if not imported.
+        /**
+         * Detect map construction using fully qualified reference if not imported.
+         * This specifically flags the constructor, and not usages of the map after it is created.
+         */
         override fun visitQualifiedReferenceExpression(node: UQualifiedReferenceExpression) {
-            if (node.selector is USimpleNameReferenceExpression) {
-                val name = node.selector as USimpleNameReferenceExpression
-                if (CONCURRENT_HASHMAP == name.identifier) {
-                    val incident = Incident(context)
-                        .issue(ISSUE)
-                        .location(context.getLocation(node))
-                        .message("Detected ConcurrentHashMap usage.")
-                        .scope(node)
-                    context.report(incident)
+            val resolved = node.resolve()
+            // In Kotlin, the resolved node will be a method with name ConcurrentHashMap
+            // In Java, it will be the class itself
+            if ((resolved is PsiMethod && resolved.isConcurrentHashMapConstructor()) ||
+                (resolved is PsiClass && resolved.isConcurrentHashMap())) {
+                reportIncidentForNode(node)
+            }
+        }
+
+        /**
+         * Detect import.
+         */
+        override fun visitImportStatement(node: UImportStatement) {
+            if (node.importReference != null) {
+                var resolved = node.resolve()
+                if (resolved is PsiField) {
+                    resolved = resolved.containingClass
+                } else if (resolved is PsiMethod) {
+                    resolved = resolved.containingClass
+                }
+
+                if (resolved is PsiClass && resolved.isConcurrentHashMap()) {
+                    reportIncidentForNode(node)
                 }
             }
         }
 
-        // Detect import.
-        override fun visitImportStatement(node: UImportStatement) {
-            if (node.importReference != null) {
-                var resolved = node.resolve()
-                if (node.resolve() is PsiField) {
-                    resolved = (resolved as PsiField).containingClass
-                } else if (resolved is PsiMethod) {
-                    resolved = resolved.containingClass
-                }
-                if (resolved is PsiClass &&
-                    CONCURRENT_HASHMAP_QUALIFIED_NAME == resolved.qualifiedName
-                ) {
-                    val incident = Incident(context)
-                        .issue(ISSUE)
-                        .location(context.getLocation(node))
-                        .message("Detected ConcurrentHashMap usage.")
-                        .scope(node)
-                    context.report(incident)
-                }
-            }
+        /**
+         * Reports an error for ConcurrentHashMap usage at the node's location.
+         */
+        private fun reportIncidentForNode(node: UElement) {
+            val incident = Incident(context)
+                .issue(ISSUE)
+                .location(context.getLocation(node))
+                .message("Detected ConcurrentHashMap usage.")
+                .scope(node)
+            context.report(incident)
+        }
+
+        /**
+         * Check if the method is the constructor for ConcurrentHashMap (applicable for Kotlin).
+         */
+        private fun PsiMethod.isConcurrentHashMapConstructor(): Boolean {
+            return name == CONCURRENT_HASHMAP && (containingClass?.isConcurrentHashMap() ?: false)
+        }
+
+        /**
+         * Checks if the class is ConcurrentHashMap.
+         */
+        private fun PsiClass.isConcurrentHashMap(): Boolean {
+            return qualifiedName == CONCURRENT_HASHMAP_QUALIFIED_NAME
         }
     }
 
diff --git a/lint-checks/src/test/java/androidx/build/lint/BanConcurrentHashMapTest.kt b/lint-checks/src/test/java/androidx/build/lint/BanConcurrentHashMapTest.kt
index bb9acbb..cc2edd6 100644
--- a/lint-checks/src/test/java/androidx/build/lint/BanConcurrentHashMapTest.kt
+++ b/lint-checks/src/test/java/androidx/build/lint/BanConcurrentHashMapTest.kt
@@ -30,19 +30,17 @@
 ) {
 
     @Test
-    fun `Detection of ConcurrentHashMap usage in Java sources`() {
+    fun `Detection of ConcurrentHashMap import in Java sources`() {
         val input = java(
-            "src/androidx/ConcurrentHashMapUsageJava.java",
+            "src/androidx/ConcurrentHashMapImportJava.java",
             """
                 import androidx.annotation.NonNull;
                 import java.util.Map;
                 import java.util.concurrent.ConcurrentHashMap;
 
                 public class ConcurrentHashMapUsageJava {
+                    private final Map<?, ?> mMap = new ConcurrentHashMap<>();
 
-                    private final ConcurrentHashMap<?, ?> mMap = new ConcurrentHashMap<>();
-
-                    @NonNull
                     public <V, K> Map<V, K> createMap() {
                         return new ConcurrentHashMap<>();
                     }
@@ -52,7 +50,7 @@
 
         /* ktlint-disable max-line-length */
         val expected = """
-src/androidx/ConcurrentHashMapUsageJava.java:3: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
+src/androidx/ConcurrentHashMapImportJava.java:3: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
 import java.util.concurrent.ConcurrentHashMap;
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1 errors, 0 warnings
@@ -63,17 +61,50 @@
     }
 
     @Test
-    fun `Detection of ConcurrentHashMap usage in Kotlin sources`() {
+    fun `Detection of ConcurrentHashMap fully-qualified usage in Java sources`() {
+        val input = java(
+            "src/androidx/ConcurrentHashMapUsageJava.java",
+            """
+                import androidx.annotation.NonNull;
+                import java.util.Map;
+
+                public class ConcurrentHashMapUsageJava {
+                    private final Map<?, ?> mMap = new java.util.concurrent.ConcurrentHashMap<>();
+
+                    public <V, K> Map<V, K> createMap() {
+                        return new java.util.concurrent.ConcurrentHashMap<>();
+                    }
+                }
+            """.trimIndent()
+        )
+
+        /* ktlint-disable max-line-length */
+        val expected = """
+src/androidx/ConcurrentHashMapUsageJava.java:5: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
+    private final Map<?, ?> mMap = new java.util.concurrent.ConcurrentHashMap<>();
+                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+src/androidx/ConcurrentHashMapUsageJava.java:8: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
+        return new java.util.concurrent.ConcurrentHashMap<>();
+                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+2 errors, 0 warnings
+        """.trimIndent()
+        /* ktlint-enable max-line-length */
+
+        check(input).expect(expected)
+    }
+
+    @Test
+    fun `Detection of ConcurrentHashMap import in Kotlin sources`() {
         val input = kotlin(
-            "src/androidx/ConcurrentHashMapUsageKotlin.kt",
+            "src/androidx/ConcurrentHashMapImportKotlin.kt",
             """
                 package androidx
 
                 import java.util.concurrent.ConcurrentHashMap
 
-                @Suppress("unused")
                 class ConcurrentHashMapUsageKotlin {
                     private val mMap: ConcurrentHashMap<*, *> = ConcurrentHashMap<Any, Any>()
+
                     fun <V, K> createMap(): Map<V, K> {
                         return ConcurrentHashMap()
                     }
@@ -83,7 +114,7 @@
 
         /* ktlint-disable max-line-length */
         val expected = """
-src/androidx/ConcurrentHashMapUsageKotlin.kt:3: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
+src/androidx/ConcurrentHashMapImportKotlin.kt:3: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
 import java.util.concurrent.ConcurrentHashMap
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1 errors, 0 warnings
@@ -95,7 +126,88 @@
                 *stubs,
                 input
             )
-            .skipTestModes(TestMode.IMPORT_ALIAS) // b/203124716
+            // This fails in IMPORT_ALIAS mode because changing the import line changes the error.
+            // It fails in FULLY_QUALIFIED mode because more errors occur when the fully-qualified
+            // class is used. These cases are tested separately.
+            .skipTestModes(TestMode.IMPORT_ALIAS, TestMode.FULLY_QUALIFIED)
+            .run()
+            .expect(expected)
+    }
+
+    @Test
+    fun `Detection of ConcurrentHashMap fully-qualified usage in Kotlin sources`() {
+        val input = kotlin(
+            "src/androidx/ConcurrentHashMapUsageKotlin.kt",
+            """
+                package androidx
+
+                class ConcurrentHashMapUsageKotlin {
+                    private val mMap: Map<*, *> = java.util.concurrent.ConcurrentHashMap<Any, Any>()
+
+                    fun <V, K> createMap(): Map<V, K> {
+                        return java.util.concurrent.ConcurrentHashMap()
+                    }
+                }
+            """.trimIndent()
+        )
+
+        /* ktlint-disable max-line-length */
+        val expected = """
+src/androidx/ConcurrentHashMapUsageKotlin.kt:4: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
+    private val mMap: Map<*, *> = java.util.concurrent.ConcurrentHashMap<Any, Any>()
+                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+src/androidx/ConcurrentHashMapUsageKotlin.kt:7: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
+        return java.util.concurrent.ConcurrentHashMap()
+               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+2 errors, 0 warnings
+        """.trimIndent()
+        /* ktlint-enable max-line-length */
+
+        lint()
+            .files(
+                *stubs,
+                input
+            )
+            .run()
+            .expect(expected)
+    }
+
+    @Test
+    fun `Detection of ConcurrentHashMap import alias in Kotlin sources`() {
+        val input = kotlin(
+            "src/androidx/ConcurrentHashMapUsageAliasKotlin.kt",
+            """
+                package androidx
+
+                import java.util.concurrent.ConcurrentHashMap as NewClassName
+
+                class ConcurrentHashMapUsageAliasKotlin {
+                    private val mMap: Map<*, *> = NewClassName<Any, Any>()
+
+                    fun <V, K> createMap(): Map<V, K> {
+                        return NewClassName()
+                    }
+                }
+            """.trimIndent()
+        )
+
+        /* ktlint-disable max-line-length */
+        val expected = """
+src/androidx/ConcurrentHashMapUsageAliasKotlin.kt:3: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
+import java.util.concurrent.ConcurrentHashMap as NewClassName
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+1 errors, 0 warnings
+        """.trimIndent()
+        /* ktlint-enable max-line-length */
+
+        lint()
+            .files(
+                *stubs,
+                input
+            )
+            // In FULLY_QUALIFIED test mode, more errors occur when the fully-qualified class is
+            // used. This case is tested separately.
+            .skipTestModes(TestMode.FULLY_QUALIFIED)
             .run()
             .expect(expected)
     }
diff --git a/media/version-compat-tests/current/client/build.gradle b/media/version-compat-tests/current/client/build.gradle
index fec712a..6950588 100644
--- a/media/version-compat-tests/current/client/build.gradle
+++ b/media/version-compat-tests/current/client/build.gradle
@@ -19,6 +19,10 @@
     id("com.android.library")
 }
 
+android {
+    namespace "android.support.mediacompat.client"
+}
+
 dependencies {
     androidTestImplementation(project(":media:media"))
     androidTestImplementation(project(":media:version-compat-tests:lib"))
diff --git a/media/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml b/media/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
index 1f737c9..aaf0585 100644
--- a/media/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
+++ b/media/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
@@ -14,8 +14,7 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.mediacompat.client.test">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
     <queries>
         <package android:name="android.support.mediacompat.service.test" />
     </queries>
diff --git a/media/version-compat-tests/current/client/src/main/AndroidManifest.xml b/media/version-compat-tests/current/client/src/main/AndroidManifest.xml
deleted file mode 100644
index 9724d2b..0000000
--- a/media/version-compat-tests/current/client/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2017 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.
--->
-<manifest package="android.support.mediacompat.client"/>
diff --git a/media/version-compat-tests/current/service/build.gradle b/media/version-compat-tests/current/service/build.gradle
index fec712a..6374b29 100644
--- a/media/version-compat-tests/current/service/build.gradle
+++ b/media/version-compat-tests/current/service/build.gradle
@@ -19,6 +19,10 @@
     id("com.android.library")
 }
 
+android {
+    namespace "android.support.mediacompat.service"
+}
+
 dependencies {
     androidTestImplementation(project(":media:media"))
     androidTestImplementation(project(":media:version-compat-tests:lib"))
diff --git a/media/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml b/media/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
index 344b26a..dea570c 100644
--- a/media/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
+++ b/media/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
@@ -14,8 +14,7 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.mediacompat.service.test">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
     <application>
         <receiver
diff --git a/media/version-compat-tests/current/service/src/main/AndroidManifest.xml b/media/version-compat-tests/current/service/src/main/AndroidManifest.xml
deleted file mode 100644
index 5e25a83..0000000
--- a/media/version-compat-tests/current/service/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2017 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.
--->
-<manifest package="android.support.mediacompat.service"/>
diff --git a/media/version-compat-tests/lib/src/main/AndroidManifest.xml b/media/version-compat-tests/lib/src/main/AndroidManifest.xml
deleted file mode 100644
index 4cea376..0000000
--- a/media/version-compat-tests/lib/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2017 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.
--->
-<manifest />
diff --git a/media/version-compat-tests/previous/client/build.gradle b/media/version-compat-tests/previous/client/build.gradle
index a7fe5f5..c199f15 100644
--- a/media/version-compat-tests/previous/client/build.gradle
+++ b/media/version-compat-tests/previous/client/build.gradle
@@ -19,6 +19,10 @@
     id("com.android.library")
 }
 
+android {
+    namespace "android.support.mediacompat.client"
+}
+
 dependencies {
     androidTestImplementation("androidx.media:media:1.4.1")
     androidTestImplementation(project(":media:version-compat-tests:lib"))
diff --git a/media/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml b/media/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
index 1f737c9..aaf0585 100644
--- a/media/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
+++ b/media/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
@@ -14,8 +14,7 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.mediacompat.client.test">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
     <queries>
         <package android:name="android.support.mediacompat.service.test" />
     </queries>
diff --git a/media/version-compat-tests/previous/client/src/main/AndroidManifest.xml b/media/version-compat-tests/previous/client/src/main/AndroidManifest.xml
deleted file mode 100644
index 9724d2b..0000000
--- a/media/version-compat-tests/previous/client/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2017 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.
--->
-<manifest package="android.support.mediacompat.client"/>
diff --git a/media/version-compat-tests/previous/service/build.gradle b/media/version-compat-tests/previous/service/build.gradle
index a7fe5f5..4695e46 100644
--- a/media/version-compat-tests/previous/service/build.gradle
+++ b/media/version-compat-tests/previous/service/build.gradle
@@ -19,6 +19,10 @@
     id("com.android.library")
 }
 
+android {
+    namespace "android.support.mediacompat.service"
+}
+
 dependencies {
     androidTestImplementation("androidx.media:media:1.4.1")
     androidTestImplementation(project(":media:version-compat-tests:lib"))
diff --git a/media/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml b/media/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
index 344b26a..dea570c 100644
--- a/media/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
+++ b/media/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
@@ -14,8 +14,7 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.mediacompat.service.test">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
     <application>
         <receiver
diff --git a/media/version-compat-tests/previous/service/src/main/AndroidManifest.xml b/media/version-compat-tests/previous/service/src/main/AndroidManifest.xml
deleted file mode 100644
index 5e25a83..0000000
--- a/media/version-compat-tests/previous/service/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2017 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.
--->
-<manifest package="android.support.mediacompat.service"/>
diff --git a/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer2Test.java b/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer2Test.java
index d2b5aa5..9510928 100644
--- a/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer2Test.java
+++ b/media2/media2-player/src/androidTest/java/androidx/media2/player/MediaPlayer2Test.java
@@ -1090,7 +1090,7 @@
     }
     */
 
-    @FlakyTest(bugId = 187340262)
+    @Ignore("b/213625878")
     @Test
     @LargeTest
     public void playbackRate() throws Exception {
diff --git a/media2/media2-session/version-compat-tests/common/src/main/AndroidManifest.xml b/media2/media2-session/version-compat-tests/common/src/main/AndroidManifest.xml
deleted file mode 100644
index 4cf4915..0000000
--- a/media2/media2-session/version-compat-tests/common/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2018 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.
--->
-<manifest />
diff --git a/media2/media2-session/version-compat-tests/current/client/build.gradle b/media2/media2-session/version-compat-tests/current/client/build.gradle
index 7933e6d..147a6a7 100644
--- a/media2/media2-session/version-compat-tests/current/client/build.gradle
+++ b/media2/media2-session/version-compat-tests/current/client/build.gradle
@@ -33,6 +33,7 @@
     defaultConfig {
         minSdkVersion 16
     }
+    namespace "androidx.media2.test.client"
 }
 
 androidx {
diff --git a/media2/media2-session/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml b/media2/media2-session/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
index ce9acde..1cb0b1d3 100644
--- a/media2/media2-session/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
+++ b/media2/media2-session/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
@@ -14,8 +14,7 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.media2.test.client.test">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
     <application android:supportsRtl="true">
         <activity
diff --git a/media2/media2-session/version-compat-tests/current/client/src/main/AndroidManifest.xml b/media2/media2-session/version-compat-tests/current/client/src/main/AndroidManifest.xml
deleted file mode 100644
index 185bf1e..0000000
--- a/media2/media2-session/version-compat-tests/current/client/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2018 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.
--->
-<manifest package="androidx.media2.test.client"/>
diff --git a/media2/media2-session/version-compat-tests/current/service/build.gradle b/media2/media2-session/version-compat-tests/current/service/build.gradle
index 2a87a6a..61b94fc 100644
--- a/media2/media2-session/version-compat-tests/current/service/build.gradle
+++ b/media2/media2-session/version-compat-tests/current/service/build.gradle
@@ -32,6 +32,7 @@
     defaultConfig {
         minSdkVersion 16
     }
+    namespace "androidx.media2.test.service"
 }
 
 androidx {
diff --git a/media2/media2-session/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml b/media2/media2-session/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
index 3a1f4f4..d06e43a 100644
--- a/media2/media2-session/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
+++ b/media2/media2-session/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
@@ -14,8 +14,7 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.media2.test.service.test">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
     <application>
         <receiver
diff --git a/media2/media2-session/version-compat-tests/current/service/src/main/AndroidManifest.xml b/media2/media2-session/version-compat-tests/current/service/src/main/AndroidManifest.xml
deleted file mode 100644
index 15fbd02..0000000
--- a/media2/media2-session/version-compat-tests/current/service/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2018 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.
--->
-<manifest package="androidx.media2.test.service"/>
diff --git a/media2/media2-session/version-compat-tests/previous/client/build.gradle b/media2/media2-session/version-compat-tests/previous/client/build.gradle
index 65dec59..634a725 100644
--- a/media2/media2-session/version-compat-tests/previous/client/build.gradle
+++ b/media2/media2-session/version-compat-tests/previous/client/build.gradle
@@ -33,6 +33,7 @@
     defaultConfig {
         minSdkVersion 16
     }
+    namespace "androidx.media2.test.client"
 }
 
 androidx {
diff --git a/media2/media2-session/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml b/media2/media2-session/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
index ce9acde..1cb0b1d3 100644
--- a/media2/media2-session/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
+++ b/media2/media2-session/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
@@ -14,8 +14,7 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.media2.test.client.test">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
     <application android:supportsRtl="true">
         <activity
diff --git a/media2/media2-session/version-compat-tests/previous/client/src/main/AndroidManifest.xml b/media2/media2-session/version-compat-tests/previous/client/src/main/AndroidManifest.xml
deleted file mode 100644
index 185bf1e..0000000
--- a/media2/media2-session/version-compat-tests/previous/client/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2018 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.
--->
-<manifest package="androidx.media2.test.client"/>
diff --git a/media2/media2-session/version-compat-tests/previous/service/build.gradle b/media2/media2-session/version-compat-tests/previous/service/build.gradle
index db6d7a6..48791a6 100644
--- a/media2/media2-session/version-compat-tests/previous/service/build.gradle
+++ b/media2/media2-session/version-compat-tests/previous/service/build.gradle
@@ -32,6 +32,7 @@
     defaultConfig {
         minSdkVersion 16
     }
+    namespace "androidx.media2.test.service"
 }
 
 androidx {
diff --git a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
index 3a1f4f4..d06e43a 100644
--- a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
+++ b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
@@ -14,8 +14,7 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.media2.test.service.test">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
     <application>
         <receiver
diff --git a/media2/media2-session/version-compat-tests/previous/service/src/main/AndroidManifest.xml b/media2/media2-session/version-compat-tests/previous/service/src/main/AndroidManifest.xml
deleted file mode 100644
index 15fbd02..0000000
--- a/media2/media2-session/version-compat-tests/previous/service/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright 2018 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.
--->
-<manifest package="androidx.media2.test.service"/>
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt
index 5d15eed..dfce454 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavType.kt
@@ -68,7 +68,10 @@
 
     /**
      * Parse a value of this type from a String and then combine that
-     * parsed value with the given previousValue of the same type.
+     * parsed value with the given previousValue of the same type to
+     * provide a new value that contains both the new and previous value.
+     *
+     * By default, the given value will replace the previousValue.
      *
      * @param value string representation of a value of this type
      * @param previousValue previously parsed value of this type
diff --git a/navigation/navigation-dynamic-features-fragment/src/androidTest/java/androidx/navigation/dynamicfeatures/fragment/ui/DefaultProgressFragmentTest.kt b/navigation/navigation-dynamic-features-fragment/src/androidTest/java/androidx/navigation/dynamicfeatures/fragment/ui/DefaultProgressFragmentTest.kt
index 39dcd18..57d781b 100644
--- a/navigation/navigation-dynamic-features-fragment/src/androidTest/java/androidx/navigation/dynamicfeatures/fragment/ui/DefaultProgressFragmentTest.kt
+++ b/navigation/navigation-dynamic-features-fragment/src/androidTest/java/androidx/navigation/dynamicfeatures/fragment/ui/DefaultProgressFragmentTest.kt
@@ -19,6 +19,7 @@
 import androidx.navigation.dynamicfeatures.fragment.R as mainR
 import androidx.navigation.dynamicfeatures.fragment.test.R as testR
 import android.widget.TextView
+import androidx.lifecycle.Observer
 import androidx.lifecycle.ViewModelProvider
 import androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment
 import androidx.navigation.dynamicfeatures.fragment.NavigationActivity
@@ -27,6 +28,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import androidx.testutils.withActivity
+import com.google.android.play.core.splitinstall.SplitInstallSessionState
 import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus
 import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.CountDownLatch
@@ -68,11 +70,16 @@
                 // the test to wait for the failure signal from the splitInstall session. To do that
                 // we observe the livedata of the DefaultProgressFragment's viewModel, and wait for
                 // it to fail before we check for test failure.
-                viewModel.installMonitor!!.status.observe(defaultProgressFragment) {
-                    if (it.status() == SplitInstallSessionStatus.FAILED) {
-                        failureCountdownLatch.countDown()
+                val liveData = viewModel.installMonitor!!.status
+                val observer = object : Observer<SplitInstallSessionState> {
+                    override fun onChanged(state: SplitInstallSessionState) {
+                        if (state.status() == SplitInstallSessionStatus.FAILED) {
+                            liveData.removeObserver(this)
+                            failureCountdownLatch.countDown()
+                        }
                     }
                 }
+                liveData.observe(defaultProgressFragment, observer)
             }
 
             assertThat(failureCountdownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
diff --git a/playground-common/gradle/wrapper/gradle-wrapper.properties b/playground-common/gradle/wrapper/gradle-wrapper.properties
index 26e62a1..7e65b70 100644
--- a/playground-common/gradle/wrapper/gradle-wrapper.properties
+++ b/playground-common/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-rc-2-bin.zip
+distributionSha256Sum=ba761aa1563f5d893d1a6e7ddca48bbdc4385fdd527974e6472b873b7eae9a32
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/preference/preference/api/current.txt b/preference/preference/api/current.txt
index 19e1320..ee92871 100644
--- a/preference/preference/api/current.txt
+++ b/preference/preference/api/current.txt
@@ -72,7 +72,7 @@
 
   public class EditTextPreferenceDialogFragmentCompat extends androidx.preference.PreferenceDialogFragmentCompat {
     ctor public EditTextPreferenceDialogFragmentCompat();
-    method public static androidx.preference.EditTextPreferenceDialogFragmentCompat newInstance(String!);
+    method public static androidx.preference.EditTextPreferenceDialogFragmentCompat newInstance(String);
     method public void onDialogClosed(boolean);
   }
 
diff --git a/preference/preference/api/public_plus_experimental_current.txt b/preference/preference/api/public_plus_experimental_current.txt
index 19e1320..ee92871 100644
--- a/preference/preference/api/public_plus_experimental_current.txt
+++ b/preference/preference/api/public_plus_experimental_current.txt
@@ -72,7 +72,7 @@
 
   public class EditTextPreferenceDialogFragmentCompat extends androidx.preference.PreferenceDialogFragmentCompat {
     ctor public EditTextPreferenceDialogFragmentCompat();
-    method public static androidx.preference.EditTextPreferenceDialogFragmentCompat newInstance(String!);
+    method public static androidx.preference.EditTextPreferenceDialogFragmentCompat newInstance(String);
     method public void onDialogClosed(boolean);
   }
 
diff --git a/preference/preference/api/restricted_current.txt b/preference/preference/api/restricted_current.txt
index 1611229..6b4f873 100644
--- a/preference/preference/api/restricted_current.txt
+++ b/preference/preference/api/restricted_current.txt
@@ -72,7 +72,7 @@
 
   public class EditTextPreferenceDialogFragmentCompat extends androidx.preference.PreferenceDialogFragmentCompat {
     ctor public EditTextPreferenceDialogFragmentCompat();
-    method public static androidx.preference.EditTextPreferenceDialogFragmentCompat newInstance(String!);
+    method public static androidx.preference.EditTextPreferenceDialogFragmentCompat newInstance(String);
     method public void onDialogClosed(boolean);
   }
 
diff --git a/preference/preference/src/main/java/androidx/preference/EditTextPreferenceDialogFragmentCompat.java b/preference/preference/src/main/java/androidx/preference/EditTextPreferenceDialogFragmentCompat.java
index 83f81b5..020e1b1 100644
--- a/preference/preference/src/main/java/androidx/preference/EditTextPreferenceDialogFragmentCompat.java
+++ b/preference/preference/src/main/java/androidx/preference/EditTextPreferenceDialogFragmentCompat.java
@@ -47,7 +47,7 @@
     private static final int SHOW_REQUEST_TIMEOUT = 1000;
 
     @NonNull
-    public static EditTextPreferenceDialogFragmentCompat newInstance(String key) {
+    public static EditTextPreferenceDialogFragmentCompat newInstance(@NonNull String key) {
         final EditTextPreferenceDialogFragmentCompat
                 fragment = new EditTextPreferenceDialogFragmentCompat();
         final Bundle b = new Bundle(1);
diff --git a/recommendation/recommendation/api/api_lint.ignore b/recommendation/recommendation/api/api_lint.ignore
index dd512ff..09ce304 100644
--- a/recommendation/recommendation/api/api_lint.ignore
+++ b/recommendation/recommendation/api/api_lint.ignore
@@ -11,144 +11,20 @@
     androidx.recommendation.app.ContentRecommendation does not declare a `getProgress()` method matching method androidx.recommendation.app.ContentRecommendation.Builder.setProgress(int,int)
 
 
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getBackgroundImageUri():
-    Missing nullability on method `getBackgroundImageUri` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getContentImage():
-    Missing nullability on method `getContentImage` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getContentIntent():
-    Missing nullability on method `getContentIntent` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getContentTypes():
-    Missing nullability on method `getContentTypes` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getDismissIntent():
-    Missing nullability on method `getDismissIntent` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getGenres():
-    Missing nullability on method `getGenres` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getGroup():
-    Missing nullability on method `getGroup` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getIdTag():
-    Missing nullability on method `getIdTag` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getMaturityRating():
-    Missing nullability on method `getMaturityRating` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getNotificationObject(android.content.Context):
-    Missing nullability on method `getNotificationObject` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getNotificationObject(android.content.Context) parameter #0:
-    Missing nullability on parameter `context` in method `getNotificationObject`
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getPricingType():
-    Missing nullability on method `getPricingType` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getPricingValue():
-    Missing nullability on method `getPricingValue` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getPrimaryContentType():
-    Missing nullability on method `getPrimaryContentType` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getSortKey():
-    Missing nullability on method `getSortKey` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getSourceName():
-    Missing nullability on method `getSourceName` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getText():
-    Missing nullability on method `getText` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#getTitle():
-    Missing nullability on method `getTitle` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation#setGroup(String) parameter #0:
-    Missing nullability on parameter `groupTag` in method `setGroup`
-MissingNullability: androidx.recommendation.app.ContentRecommendation#setSortKey(String) parameter #0:
-    Missing nullability on parameter `sortKey` in method `setSortKey`
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#build():
-    Missing nullability on method `build` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setAutoDismiss(boolean):
-    Missing nullability on method `setAutoDismiss` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setBackgroundImageUri(String):
-    Missing nullability on method `setBackgroundImageUri` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setBadgeIcon(int):
-    Missing nullability on method `setBadgeIcon` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setColor(int):
-    Missing nullability on method `setColor` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setContentImage(android.graphics.Bitmap):
-    Missing nullability on method `setContentImage` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setContentImage(android.graphics.Bitmap) parameter #0:
-    Missing nullability on parameter `image` in method `setContentImage`
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setContentIntentData(int, android.content.Intent, int, android.os.Bundle):
-    Missing nullability on method `setContentIntentData` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setContentIntentData(int, android.content.Intent, int, android.os.Bundle) parameter #1:
-    Missing nullability on parameter `intent` in method `setContentIntentData`
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setContentTypes(String[]):
-    Missing nullability on method `setContentTypes` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setContentTypes(String[]) parameter #0:
-    Missing nullability on parameter `types` in method `setContentTypes`
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setDismissIntentData(int, android.content.Intent, int, android.os.Bundle):
-    Missing nullability on method `setDismissIntentData` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setGenres(String[]):
-    Missing nullability on method `setGenres` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setGenres(String[]) parameter #0:
-    Missing nullability on parameter `genres` in method `setGenres`
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setGroup(String):
-    Missing nullability on method `setGroup` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setIdTag(String):
-    Missing nullability on method `setIdTag` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setIdTag(String) parameter #0:
-    Missing nullability on parameter `idTag` in method `setIdTag`
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setMaturityRating(String):
-    Missing nullability on method `setMaturityRating` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setMaturityRating(String) parameter #0:
-    Missing nullability on parameter `maturityRating` in method `setMaturityRating`
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setPricingInformation(String, String):
-    Missing nullability on method `setPricingInformation` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setPricingInformation(String, String) parameter #0:
-    Missing nullability on parameter `priceType` in method `setPricingInformation`
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setProgress(int, int):
-    Missing nullability on method `setProgress` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setRunningTime(long):
-    Missing nullability on method `setRunningTime` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setSortKey(String):
-    Missing nullability on method `setSortKey` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setSourceName(String):
-    Missing nullability on method `setSourceName` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setStatus(int):
-    Missing nullability on method `setStatus` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setText(String):
-    Missing nullability on method `setText` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setTitle(String):
-    Missing nullability on method `setTitle` return
-MissingNullability: androidx.recommendation.app.ContentRecommendation.Builder#setTitle(String) parameter #0:
-    Missing nullability on parameter `title` in method `setTitle`
-MissingNullability: androidx.recommendation.app.RecommendationExtender#RecommendationExtender(android.app.Notification) parameter #0:
-    Missing nullability on parameter `notif` in method `RecommendationExtender`
 MissingNullability: androidx.recommendation.app.RecommendationExtender#extend(android.app.Notification.Builder):
     Missing nullability on method `extend` return
 MissingNullability: androidx.recommendation.app.RecommendationExtender#extend(android.app.Notification.Builder) parameter #0:
     Missing nullability on parameter `builder` in method `extend`
-MissingNullability: androidx.recommendation.app.RecommendationExtender#getContentTypes():
-    Missing nullability on method `getContentTypes` return
-MissingNullability: androidx.recommendation.app.RecommendationExtender#getGenres():
-    Missing nullability on method `getGenres` return
-MissingNullability: androidx.recommendation.app.RecommendationExtender#getMaturityRating():
-    Missing nullability on method `getMaturityRating` return
-MissingNullability: androidx.recommendation.app.RecommendationExtender#getPricingType():
-    Missing nullability on method `getPricingType` return
-MissingNullability: androidx.recommendation.app.RecommendationExtender#getPricingValue():
-    Missing nullability on method `getPricingValue` return
-MissingNullability: androidx.recommendation.app.RecommendationExtender#getPrimaryContentType():
-    Missing nullability on method `getPrimaryContentType` return
-MissingNullability: androidx.recommendation.app.RecommendationExtender#setContentTypes(String[]):
-    Missing nullability on method `setContentTypes` return
-MissingNullability: androidx.recommendation.app.RecommendationExtender#setContentTypes(String[]) parameter #0:
-    Missing nullability on parameter `types` in method `setContentTypes`
-MissingNullability: androidx.recommendation.app.RecommendationExtender#setGenres(String[]):
-    Missing nullability on method `setGenres` return
-MissingNullability: androidx.recommendation.app.RecommendationExtender#setGenres(String[]) parameter #0:
-    Missing nullability on parameter `genres` in method `setGenres`
-MissingNullability: androidx.recommendation.app.RecommendationExtender#setMaturityRating(String):
-    Missing nullability on method `setMaturityRating` return
-MissingNullability: androidx.recommendation.app.RecommendationExtender#setMaturityRating(String) parameter #0:
-    Missing nullability on parameter `maturityRating` in method `setMaturityRating`
-MissingNullability: androidx.recommendation.app.RecommendationExtender#setPricingInformation(String, String):
-    Missing nullability on method `setPricingInformation` return
-MissingNullability: androidx.recommendation.app.RecommendationExtender#setPricingInformation(String, String) parameter #0:
-    Missing nullability on parameter `priceType` in method `setPricingInformation`
-MissingNullability: androidx.recommendation.app.RecommendationExtender#setPricingInformation(String, String) parameter #1:
-    Missing nullability on parameter `priceValue` in method `setPricingInformation`
-MissingNullability: androidx.recommendation.app.RecommendationExtender#setRunningTime(long):
-    Missing nullability on method `setRunningTime` return
-MissingNullability: androidx.recommendation.app.RecommendationExtender#setStatus(int):
-    Missing nullability on method `setStatus` return
+
+
+NullableCollection: androidx.recommendation.app.ContentRecommendation#getContentTypes():
+    Return type of method androidx.recommendation.app.ContentRecommendation.getContentTypes() is a nullable collection (`java.lang.String[]`); must be non-null
+NullableCollection: androidx.recommendation.app.ContentRecommendation#getGenres():
+    Return type of method androidx.recommendation.app.ContentRecommendation.getGenres() is a nullable collection (`java.lang.String[]`); must be non-null
+NullableCollection: androidx.recommendation.app.RecommendationExtender#getContentTypes():
+    Return type of method androidx.recommendation.app.RecommendationExtender.getContentTypes() is a nullable collection (`java.lang.String[]`); must be non-null
+NullableCollection: androidx.recommendation.app.RecommendationExtender#getGenres():
+    Return type of method androidx.recommendation.app.RecommendationExtender.getGenres() is a nullable collection (`java.lang.String[]`); must be non-null
 
 
 PublicTypedef: androidx.recommendation.app.ContentRecommendation.ContentMaturity:
diff --git a/recommendation/recommendation/api/current.txt b/recommendation/recommendation/api/current.txt
index f1c5204..9731349 100644
--- a/recommendation/recommendation/api/current.txt
+++ b/recommendation/recommendation/api/current.txt
@@ -2,35 +2,35 @@
 package androidx.recommendation.app {
 
   public final class ContentRecommendation {
-    method public String! getBackgroundImageUri();
+    method public String? getBackgroundImageUri();
     method public int getBadgeImageResourceId();
     method public int getColor();
-    method public android.graphics.Bitmap! getContentImage();
-    method public androidx.recommendation.app.ContentRecommendation.IntentData! getContentIntent();
-    method public String![]! getContentTypes();
-    method public androidx.recommendation.app.ContentRecommendation.IntentData! getDismissIntent();
-    method public String![]! getGenres();
-    method public String! getGroup();
-    method public String! getIdTag();
-    method public String! getMaturityRating();
-    method public android.app.Notification! getNotificationObject(android.content.Context!);
-    method public String! getPricingType();
-    method public String! getPricingValue();
-    method public String! getPrimaryContentType();
+    method public android.graphics.Bitmap? getContentImage();
+    method public androidx.recommendation.app.ContentRecommendation.IntentData? getContentIntent();
+    method public String![]? getContentTypes();
+    method public androidx.recommendation.app.ContentRecommendation.IntentData? getDismissIntent();
+    method public String![]? getGenres();
+    method public String? getGroup();
+    method public String? getIdTag();
+    method public String? getMaturityRating();
+    method public android.app.Notification getNotificationObject(android.content.Context);
+    method public String? getPricingType();
+    method public String? getPricingValue();
+    method public String? getPrimaryContentType();
     method public int getProgressMax();
     method public int getProgressValue();
     method public long getRunningTime();
-    method public String! getSortKey();
-    method public String! getSourceName();
+    method public String? getSortKey();
+    method public String? getSourceName();
     method public int getStatus();
-    method public String! getText();
-    method public String! getTitle();
+    method public String? getText();
+    method public String? getTitle();
     method public boolean hasProgressInfo();
     method public boolean isAutoDismiss();
     method public void setAutoDismiss(boolean);
-    method public void setGroup(String!);
+    method public void setGroup(String?);
     method public void setProgress(int, int);
-    method public void setSortKey(String!);
+    method public void setSortKey(String?);
     method public void setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
     field public static final String CONTENT_MATURITY_ALL = "android.contentMaturity.all";
     field public static final String CONTENT_MATURITY_HIGH = "android.contentMaturity.high";
@@ -67,27 +67,27 @@
 
   public static final class ContentRecommendation.Builder {
     ctor public ContentRecommendation.Builder();
-    method public androidx.recommendation.app.ContentRecommendation! build();
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setAutoDismiss(boolean);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setBackgroundImageUri(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setBadgeIcon(@DrawableRes int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setColor(@ColorInt int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setContentImage(android.graphics.Bitmap!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setContentIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent!, int, android.os.Bundle?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setContentTypes(String![]!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setDismissIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent?, int, android.os.Bundle?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setGenres(String![]!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setGroup(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setIdTag(String!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String!, String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setProgress(int, int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setRunningTime(long);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setSortKey(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setSourceName(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setText(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setTitle(String!);
+    method public androidx.recommendation.app.ContentRecommendation build();
+    method public androidx.recommendation.app.ContentRecommendation.Builder setAutoDismiss(boolean);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setBackgroundImageUri(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setBadgeIcon(@DrawableRes int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setColor(@ColorInt int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setContentImage(android.graphics.Bitmap);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setContentIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent, int, android.os.Bundle?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setContentTypes(String![]);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setDismissIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent?, int, android.os.Bundle?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setGenres(String![]?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setGroup(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setIdTag(String);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String, String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setProgress(int, int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setRunningTime(long);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setSortKey(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setSourceName(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setText(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setTitle(String);
   }
 
   @StringDef({androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_ALL, androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_LOW, androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_MEDIUM, androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_HIGH}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentRecommendation.ContentMaturity {
@@ -111,22 +111,22 @@
 
   public final class RecommendationExtender implements android.app.Notification.Extender {
     ctor public RecommendationExtender();
-    ctor public RecommendationExtender(android.app.Notification!);
+    ctor public RecommendationExtender(android.app.Notification);
     method public android.app.Notification.Builder! extend(android.app.Notification.Builder!);
-    method public String![]! getContentTypes();
-    method public String![]! getGenres();
-    method public String! getMaturityRating();
-    method public String! getPricingType();
-    method public String! getPricingValue();
-    method public String! getPrimaryContentType();
+    method public String![]? getContentTypes();
+    method public String![]? getGenres();
+    method public String? getMaturityRating();
+    method public String? getPricingType();
+    method public String? getPricingValue();
+    method public String? getPrimaryContentType();
     method public long getRunningTime();
     method public int getStatus();
-    method public androidx.recommendation.app.RecommendationExtender! setContentTypes(String![]!);
-    method public androidx.recommendation.app.RecommendationExtender! setGenres(String![]!);
-    method public androidx.recommendation.app.RecommendationExtender! setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String!);
-    method public androidx.recommendation.app.RecommendationExtender! setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String!, String!);
-    method public androidx.recommendation.app.RecommendationExtender! setRunningTime(long);
-    method public androidx.recommendation.app.RecommendationExtender! setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
+    method public androidx.recommendation.app.RecommendationExtender setContentTypes(String![]?);
+    method public androidx.recommendation.app.RecommendationExtender setGenres(String![]?);
+    method public androidx.recommendation.app.RecommendationExtender setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String?);
+    method public androidx.recommendation.app.RecommendationExtender setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String?, String?);
+    method public androidx.recommendation.app.RecommendationExtender setRunningTime(long);
+    method public androidx.recommendation.app.RecommendationExtender setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
   }
 
 }
diff --git a/recommendation/recommendation/api/public_plus_experimental_current.txt b/recommendation/recommendation/api/public_plus_experimental_current.txt
index f1c5204..9731349 100644
--- a/recommendation/recommendation/api/public_plus_experimental_current.txt
+++ b/recommendation/recommendation/api/public_plus_experimental_current.txt
@@ -2,35 +2,35 @@
 package androidx.recommendation.app {
 
   public final class ContentRecommendation {
-    method public String! getBackgroundImageUri();
+    method public String? getBackgroundImageUri();
     method public int getBadgeImageResourceId();
     method public int getColor();
-    method public android.graphics.Bitmap! getContentImage();
-    method public androidx.recommendation.app.ContentRecommendation.IntentData! getContentIntent();
-    method public String![]! getContentTypes();
-    method public androidx.recommendation.app.ContentRecommendation.IntentData! getDismissIntent();
-    method public String![]! getGenres();
-    method public String! getGroup();
-    method public String! getIdTag();
-    method public String! getMaturityRating();
-    method public android.app.Notification! getNotificationObject(android.content.Context!);
-    method public String! getPricingType();
-    method public String! getPricingValue();
-    method public String! getPrimaryContentType();
+    method public android.graphics.Bitmap? getContentImage();
+    method public androidx.recommendation.app.ContentRecommendation.IntentData? getContentIntent();
+    method public String![]? getContentTypes();
+    method public androidx.recommendation.app.ContentRecommendation.IntentData? getDismissIntent();
+    method public String![]? getGenres();
+    method public String? getGroup();
+    method public String? getIdTag();
+    method public String? getMaturityRating();
+    method public android.app.Notification getNotificationObject(android.content.Context);
+    method public String? getPricingType();
+    method public String? getPricingValue();
+    method public String? getPrimaryContentType();
     method public int getProgressMax();
     method public int getProgressValue();
     method public long getRunningTime();
-    method public String! getSortKey();
-    method public String! getSourceName();
+    method public String? getSortKey();
+    method public String? getSourceName();
     method public int getStatus();
-    method public String! getText();
-    method public String! getTitle();
+    method public String? getText();
+    method public String? getTitle();
     method public boolean hasProgressInfo();
     method public boolean isAutoDismiss();
     method public void setAutoDismiss(boolean);
-    method public void setGroup(String!);
+    method public void setGroup(String?);
     method public void setProgress(int, int);
-    method public void setSortKey(String!);
+    method public void setSortKey(String?);
     method public void setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
     field public static final String CONTENT_MATURITY_ALL = "android.contentMaturity.all";
     field public static final String CONTENT_MATURITY_HIGH = "android.contentMaturity.high";
@@ -67,27 +67,27 @@
 
   public static final class ContentRecommendation.Builder {
     ctor public ContentRecommendation.Builder();
-    method public androidx.recommendation.app.ContentRecommendation! build();
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setAutoDismiss(boolean);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setBackgroundImageUri(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setBadgeIcon(@DrawableRes int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setColor(@ColorInt int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setContentImage(android.graphics.Bitmap!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setContentIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent!, int, android.os.Bundle?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setContentTypes(String![]!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setDismissIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent?, int, android.os.Bundle?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setGenres(String![]!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setGroup(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setIdTag(String!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String!, String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setProgress(int, int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setRunningTime(long);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setSortKey(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setSourceName(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setText(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setTitle(String!);
+    method public androidx.recommendation.app.ContentRecommendation build();
+    method public androidx.recommendation.app.ContentRecommendation.Builder setAutoDismiss(boolean);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setBackgroundImageUri(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setBadgeIcon(@DrawableRes int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setColor(@ColorInt int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setContentImage(android.graphics.Bitmap);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setContentIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent, int, android.os.Bundle?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setContentTypes(String![]);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setDismissIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent?, int, android.os.Bundle?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setGenres(String![]?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setGroup(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setIdTag(String);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String, String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setProgress(int, int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setRunningTime(long);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setSortKey(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setSourceName(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setText(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setTitle(String);
   }
 
   @StringDef({androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_ALL, androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_LOW, androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_MEDIUM, androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_HIGH}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentRecommendation.ContentMaturity {
@@ -111,22 +111,22 @@
 
   public final class RecommendationExtender implements android.app.Notification.Extender {
     ctor public RecommendationExtender();
-    ctor public RecommendationExtender(android.app.Notification!);
+    ctor public RecommendationExtender(android.app.Notification);
     method public android.app.Notification.Builder! extend(android.app.Notification.Builder!);
-    method public String![]! getContentTypes();
-    method public String![]! getGenres();
-    method public String! getMaturityRating();
-    method public String! getPricingType();
-    method public String! getPricingValue();
-    method public String! getPrimaryContentType();
+    method public String![]? getContentTypes();
+    method public String![]? getGenres();
+    method public String? getMaturityRating();
+    method public String? getPricingType();
+    method public String? getPricingValue();
+    method public String? getPrimaryContentType();
     method public long getRunningTime();
     method public int getStatus();
-    method public androidx.recommendation.app.RecommendationExtender! setContentTypes(String![]!);
-    method public androidx.recommendation.app.RecommendationExtender! setGenres(String![]!);
-    method public androidx.recommendation.app.RecommendationExtender! setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String!);
-    method public androidx.recommendation.app.RecommendationExtender! setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String!, String!);
-    method public androidx.recommendation.app.RecommendationExtender! setRunningTime(long);
-    method public androidx.recommendation.app.RecommendationExtender! setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
+    method public androidx.recommendation.app.RecommendationExtender setContentTypes(String![]?);
+    method public androidx.recommendation.app.RecommendationExtender setGenres(String![]?);
+    method public androidx.recommendation.app.RecommendationExtender setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String?);
+    method public androidx.recommendation.app.RecommendationExtender setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String?, String?);
+    method public androidx.recommendation.app.RecommendationExtender setRunningTime(long);
+    method public androidx.recommendation.app.RecommendationExtender setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
   }
 
 }
diff --git a/recommendation/recommendation/api/restricted_current.txt b/recommendation/recommendation/api/restricted_current.txt
index f1c5204..9731349 100644
--- a/recommendation/recommendation/api/restricted_current.txt
+++ b/recommendation/recommendation/api/restricted_current.txt
@@ -2,35 +2,35 @@
 package androidx.recommendation.app {
 
   public final class ContentRecommendation {
-    method public String! getBackgroundImageUri();
+    method public String? getBackgroundImageUri();
     method public int getBadgeImageResourceId();
     method public int getColor();
-    method public android.graphics.Bitmap! getContentImage();
-    method public androidx.recommendation.app.ContentRecommendation.IntentData! getContentIntent();
-    method public String![]! getContentTypes();
-    method public androidx.recommendation.app.ContentRecommendation.IntentData! getDismissIntent();
-    method public String![]! getGenres();
-    method public String! getGroup();
-    method public String! getIdTag();
-    method public String! getMaturityRating();
-    method public android.app.Notification! getNotificationObject(android.content.Context!);
-    method public String! getPricingType();
-    method public String! getPricingValue();
-    method public String! getPrimaryContentType();
+    method public android.graphics.Bitmap? getContentImage();
+    method public androidx.recommendation.app.ContentRecommendation.IntentData? getContentIntent();
+    method public String![]? getContentTypes();
+    method public androidx.recommendation.app.ContentRecommendation.IntentData? getDismissIntent();
+    method public String![]? getGenres();
+    method public String? getGroup();
+    method public String? getIdTag();
+    method public String? getMaturityRating();
+    method public android.app.Notification getNotificationObject(android.content.Context);
+    method public String? getPricingType();
+    method public String? getPricingValue();
+    method public String? getPrimaryContentType();
     method public int getProgressMax();
     method public int getProgressValue();
     method public long getRunningTime();
-    method public String! getSortKey();
-    method public String! getSourceName();
+    method public String? getSortKey();
+    method public String? getSourceName();
     method public int getStatus();
-    method public String! getText();
-    method public String! getTitle();
+    method public String? getText();
+    method public String? getTitle();
     method public boolean hasProgressInfo();
     method public boolean isAutoDismiss();
     method public void setAutoDismiss(boolean);
-    method public void setGroup(String!);
+    method public void setGroup(String?);
     method public void setProgress(int, int);
-    method public void setSortKey(String!);
+    method public void setSortKey(String?);
     method public void setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
     field public static final String CONTENT_MATURITY_ALL = "android.contentMaturity.all";
     field public static final String CONTENT_MATURITY_HIGH = "android.contentMaturity.high";
@@ -67,27 +67,27 @@
 
   public static final class ContentRecommendation.Builder {
     ctor public ContentRecommendation.Builder();
-    method public androidx.recommendation.app.ContentRecommendation! build();
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setAutoDismiss(boolean);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setBackgroundImageUri(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setBadgeIcon(@DrawableRes int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setColor(@ColorInt int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setContentImage(android.graphics.Bitmap!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setContentIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent!, int, android.os.Bundle?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setContentTypes(String![]!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setDismissIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent?, int, android.os.Bundle?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setGenres(String![]!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setGroup(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setIdTag(String!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String!);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String!, String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setProgress(int, int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setRunningTime(long);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setSortKey(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setSourceName(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setText(String?);
-    method public androidx.recommendation.app.ContentRecommendation.Builder! setTitle(String!);
+    method public androidx.recommendation.app.ContentRecommendation build();
+    method public androidx.recommendation.app.ContentRecommendation.Builder setAutoDismiss(boolean);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setBackgroundImageUri(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setBadgeIcon(@DrawableRes int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setColor(@ColorInt int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setContentImage(android.graphics.Bitmap);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setContentIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent, int, android.os.Bundle?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setContentTypes(String![]);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setDismissIntentData(@androidx.recommendation.app.ContentRecommendation.IntentType int, android.content.Intent?, int, android.os.Bundle?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setGenres(String![]?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setGroup(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setIdTag(String);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String, String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setProgress(int, int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setRunningTime(long);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setSortKey(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setSourceName(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setText(String?);
+    method public androidx.recommendation.app.ContentRecommendation.Builder setTitle(String);
   }
 
   @StringDef({androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_ALL, androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_LOW, androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_MEDIUM, androidx.recommendation.app.ContentRecommendation.CONTENT_MATURITY_HIGH}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentRecommendation.ContentMaturity {
@@ -111,22 +111,22 @@
 
   public final class RecommendationExtender implements android.app.Notification.Extender {
     ctor public RecommendationExtender();
-    ctor public RecommendationExtender(android.app.Notification!);
+    ctor public RecommendationExtender(android.app.Notification);
     method public android.app.Notification.Builder! extend(android.app.Notification.Builder!);
-    method public String![]! getContentTypes();
-    method public String![]! getGenres();
-    method public String! getMaturityRating();
-    method public String! getPricingType();
-    method public String! getPricingValue();
-    method public String! getPrimaryContentType();
+    method public String![]? getContentTypes();
+    method public String![]? getGenres();
+    method public String? getMaturityRating();
+    method public String? getPricingType();
+    method public String? getPricingValue();
+    method public String? getPrimaryContentType();
     method public long getRunningTime();
     method public int getStatus();
-    method public androidx.recommendation.app.RecommendationExtender! setContentTypes(String![]!);
-    method public androidx.recommendation.app.RecommendationExtender! setGenres(String![]!);
-    method public androidx.recommendation.app.RecommendationExtender! setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String!);
-    method public androidx.recommendation.app.RecommendationExtender! setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String!, String!);
-    method public androidx.recommendation.app.RecommendationExtender! setRunningTime(long);
-    method public androidx.recommendation.app.RecommendationExtender! setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
+    method public androidx.recommendation.app.RecommendationExtender setContentTypes(String![]?);
+    method public androidx.recommendation.app.RecommendationExtender setGenres(String![]?);
+    method public androidx.recommendation.app.RecommendationExtender setMaturityRating(@androidx.recommendation.app.ContentRecommendation.ContentMaturity String?);
+    method public androidx.recommendation.app.RecommendationExtender setPricingInformation(@androidx.recommendation.app.ContentRecommendation.ContentPricing String?, String?);
+    method public androidx.recommendation.app.RecommendationExtender setRunningTime(long);
+    method public androidx.recommendation.app.RecommendationExtender setStatus(@androidx.recommendation.app.ContentRecommendation.ContentStatus int);
   }
 
 }
diff --git a/recommendation/recommendation/lint-baseline.xml b/recommendation/recommendation/lint-baseline.xml
index bab47b0..f8813c0 100644
--- a/recommendation/recommendation/lint-baseline.xml
+++ b/recommendation/recommendation/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
diff --git a/recommendation/recommendation/src/main/java/androidx/recommendation/app/ContentRecommendation.java b/recommendation/recommendation/src/main/java/androidx/recommendation/app/ContentRecommendation.java
index 87527e6..a77064e 100644
--- a/recommendation/recommendation/src/main/java/androidx/recommendation/app/ContentRecommendation.java
+++ b/recommendation/recommendation/src/main/java/androidx/recommendation/app/ContentRecommendation.java
@@ -27,6 +27,7 @@
 import androidx.annotation.ColorInt;
 import androidx.annotation.DrawableRes;
 import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.StringDef;
 
@@ -366,7 +367,7 @@
      *
      * @return The String Id tag for this recommendation.
      */
-    public String getIdTag() {
+    public @Nullable String getIdTag() {
         return mIdTag;
     }
 
@@ -375,7 +376,7 @@
      *
      * @return A String containing the recommendation content title.
      */
-    public String getTitle() {
+    public @Nullable String getTitle() {
         return mTitle;
     }
 
@@ -384,7 +385,7 @@
      *
      * @return A String containing the recommendation description text.
      */
-    public String getText() {
+    public @Nullable String getText() {
         return mText;
     }
 
@@ -393,7 +394,7 @@
      *
      * @return A String containing the recommendation source name.
      */
-    public String getSourceName() {
+    public @Nullable String getSourceName() {
         return mSourceName;
     }
 
@@ -402,7 +403,7 @@
      *
      * @return A Bitmap containing the recommendation image.
      */
-    public Bitmap getContentImage() {
+    public @Nullable Bitmap getContentImage() {
         return mContentImage;
     }
 
@@ -423,7 +424,7 @@
      *
      * @return A Content URI pointing to the recommendation background image.
      */
-    public String getBackgroundImageUri() {
+    public @Nullable String getBackgroundImageUri() {
         return mBackgroundImageUri;
     }
 
@@ -447,7 +448,7 @@
      *
      * @param groupTag A String containing the group ID tag for this recommendation.
      */
-    public void setGroup(String groupTag) {
+    public void setGroup(@Nullable String groupTag) {
         mGroup = groupTag;
     }
 
@@ -456,7 +457,7 @@
      *
      * @return A String containing the group ID tag for this recommendation.
      */
-    public String getGroup() {
+    public @Nullable String getGroup() {
         return mGroup;
     }
 
@@ -470,7 +471,7 @@
      *
      * @param sortKey A String containing the sort key for this recommendation.
      */
-    public void setSortKey(String sortKey) {
+    public void setSortKey(@Nullable String sortKey) {
         mSortKey = sortKey;
     }
 
@@ -479,7 +480,7 @@
      *
      * @return A String containing the sort key for this recommendation.
      */
-    public String getSortKey() {
+    public @Nullable String getSortKey() {
         return mSortKey;
     }
 
@@ -556,7 +557,7 @@
      * @return An IntentData object, containing the data for the Intent that gets issued when the
      *         recommendation is clicked on.
      */
-    public IntentData getContentIntent() {
+    public @Nullable IntentData getContentIntent() {
         return mContentIntentData;
     }
 
@@ -567,7 +568,7 @@
      * @return An IntentData object, containing the data for the Intent that gets issued when the
      *         recommendation is dismissed from the Home Screen.
      */
-    public IntentData getDismissIntent() {
+    public @Nullable IntentData getDismissIntent() {
         return mDismissIntentData;
     }
 
@@ -579,11 +580,11 @@
      * @return An array of predefined type tags (see the <code>CONTENT_TYPE_*</code> constants) that
      *         describe the recommended content.
      */
-    public String[] getContentTypes() {
+    public @Nullable String[] getContentTypes() {
         if (mContentTypes != null) {
             return Arrays.copyOf(mContentTypes, mContentTypes.length);
         }
-        return mContentTypes;
+        return null;
     }
 
     /**
@@ -593,7 +594,7 @@
      * @return A predefined type tag (see the <code>CONTENT_TYPE_*</code> constants) indicating the
      *         primary content type for the recommendation.
      */
-    public String getPrimaryContentType() {
+    public @Nullable String getPrimaryContentType() {
         if (mContentTypes != null && mContentTypes.length > 0) {
             return mContentTypes[0];
         }
@@ -606,11 +607,11 @@
      *
      * @return An array of genre tags that describe the recommended content.
      */
-    public String[] getGenres() {
+    public @Nullable String[] getGenres() {
         if (mContentGenres != null) {
             return Arrays.copyOf(mContentGenres, mContentGenres.length);
         }
-        return mContentGenres;
+        return null;
     }
 
     /**
@@ -619,7 +620,7 @@
      * @return A predefined tag indicating the pricing type for the content (see the <code>
      *         CONTENT_PRICING_*</code> constants).
      */
-    public String getPricingType() {
+    public @Nullable String getPricingType() {
         return mPriceType;
     }
 
@@ -630,7 +631,7 @@
      * @return A string containing a representation of the content price in the current locale and
      *         currency.
      */
-    public String getPricingValue() {
+    public @Nullable String getPricingValue() {
         return mPriceValue;
     }
 
@@ -664,7 +665,7 @@
      * @return returns a predefined tag indicating the maturity level rating for the content (see
      *         the <code>CONTENT_MATURITY_*</code> constants).
      */
-    public String getMaturityRating() {
+    public @Nullable String getMaturityRating() {
         return mMaturityRating;
     }
 
@@ -747,7 +748,7 @@
          * @param idTag A String tag identifier for this recommendation.
          * @return The Builder object, for chaining.
          */
-        public Builder setIdTag(String idTag) {
+        public @NonNull Builder setIdTag(@NonNull String idTag) {
             mBuilderIdTag = checkNotNull(idTag);
             return this;
         }
@@ -758,7 +759,7 @@
          * @param title A String containing the recommendation content title.
          * @return The Builder object, for chaining.
          */
-        public Builder setTitle(String title) {
+        public @NonNull Builder setTitle(@NonNull String title) {
             mBuilderTitle = checkNotNull(title);
             return this;
         }
@@ -769,7 +770,7 @@
          * @param description A String containing the recommendation description text.
          * @return The Builder object, for chaining.
          */
-        public Builder setText(@Nullable String description) {
+        public @NonNull Builder setText(@Nullable String description) {
             mBuilderText = description;
             return this;
         }
@@ -783,7 +784,7 @@
          * @param source A String containing the recommendation source name.
          * @return The Builder object, for chaining.
          */
-        public Builder setSourceName(@Nullable String source) {
+        public @NonNull Builder setSourceName(@Nullable String source) {
             mBuilderSourceName = source;
             return this;
         }
@@ -794,7 +795,7 @@
          * @param image A Bitmap containing the recommendation image.
          * @return The Builder object, for chaining.
          */
-        public Builder setContentImage(Bitmap image) {
+        public @NonNull Builder setContentImage(@NonNull Bitmap image) {
             mBuilderContentImage = checkNotNull(image);
             return this;
         }
@@ -809,7 +810,7 @@
          * @param iconResourceId An integer id for the badge icon resource.
          * @return The Builder object, for chaining.
          */
-        public Builder setBadgeIcon(@DrawableRes int iconResourceId) {
+        public @NonNull Builder setBadgeIcon(@DrawableRes int iconResourceId) {
             mBuilderBadgeIconId = iconResourceId;
             return this;
         }
@@ -821,7 +822,7 @@
          * @param imageUri A Content URI pointing to the recommendation background image.
          * @return The Builder object, for chaining.
          */
-        public Builder setBackgroundImageUri(@Nullable String imageUri) {
+        public @NonNull Builder setBackgroundImageUri(@Nullable String imageUri) {
             mBuilderBackgroundImageUri = imageUri;
             return this;
         }
@@ -833,7 +834,7 @@
          * @param color An integer value representing the accent color for this recommendation.
          * @return The Builder object, for chaining.
          */
-        public Builder setColor(@ColorInt int color) {
+        public @NonNull Builder setColor(@ColorInt int color) {
             mBuilderColor = color;
             return this;
         }
@@ -850,7 +851,7 @@
          * @param groupTag A String containing the group ID tag for this recommendation.
          * @return The Builder object, for chaining.
          */
-        public Builder setGroup(@Nullable String groupTag) {
+        public @NonNull Builder setGroup(@Nullable String groupTag) {
             mBuilderGroup = groupTag;
             return this;
         }
@@ -866,7 +867,7 @@
          * @param sortKey A String containing the sort key for this recommendation.
          * @return The Builder object, for chaining.
          */
-        public Builder setSortKey(@Nullable String sortKey) {
+        public @NonNull Builder setSortKey(@Nullable String sortKey) {
             mBuilderSortKey = sortKey;
             return this;
         }
@@ -878,7 +879,7 @@
          * @param progress The progress amount for this content. Must be in the range (0 - max).
          * @return The Builder object, for chaining.
          */
-        public Builder setProgress(int max, int progress) {
+        public @NonNull Builder setProgress(int max, int progress) {
             if (max < 0 || progress < 0) {
                 throw new IllegalArgumentException();
             }
@@ -897,7 +898,7 @@
          *            not.
          * @return The Builder object, for chaining.
          */
-        public Builder setAutoDismiss(boolean autoDismiss) {
+        public @NonNull Builder setAutoDismiss(boolean autoDismiss) {
             mBuilderAutoDismiss = autoDismiss;
             return this;
         }
@@ -920,8 +921,8 @@
          *            Activity should be started. May be null if there are no options.
          * @return The Builder object, for chaining.
          */
-        public Builder setContentIntentData(@IntentType int intentType, Intent intent,
-                int requestCode, @Nullable Bundle options) {
+        public @NonNull Builder setContentIntentData(@IntentType int intentType,
+                @NonNull Intent intent, int requestCode, @Nullable Bundle options) {
             if (intentType != INTENT_TYPE_ACTIVITY &&
                     intentType != INTENT_TYPE_BROADCAST &&
                     intentType != INTENT_TYPE_SERVICE) {
@@ -956,8 +957,8 @@
          *            Activity should be started. May be null if there are no options.
          * @return The Builder object, for chaining.
          */
-        public Builder setDismissIntentData(@IntentType int intentType, @Nullable Intent intent,
-                int requestCode, @Nullable Bundle options) {
+        public @NonNull Builder setDismissIntentData(@IntentType int intentType,
+                @Nullable Intent intent, int requestCode, @Nullable Bundle options) {
             if (intent != null) {
                 if (intentType != INTENT_TYPE_ACTIVITY &&
                         intentType != INTENT_TYPE_BROADCAST &&
@@ -985,7 +986,7 @@
          * @param types Array of predefined type tags (see the <code>CONTENT_TYPE_*</code>
          *            constants) that describe the recommended content.
          */
-        public Builder setContentTypes(String[] types) {
+        public @NonNull Builder setContentTypes(@NonNull String[] types) {
             mBuilderContentTypes = checkNotNull(types);
             return this;
         }
@@ -998,7 +999,7 @@
          *
          * @param genres Array of genre string tags that describe the recommended content.
          */
-        public Builder setGenres(String[] genres) {
+        public @NonNull Builder setGenres(@Nullable String[] genres) {
             mBuilderContentGenres = genres;
             return this;
         }
@@ -1013,7 +1014,7 @@
          * @param priceValue A string containing a representation of the content price in the
          *            current locale and currency.
          */
-        public Builder setPricingInformation(@ContentPricing String priceType,
+        public @NonNull Builder setPricingInformation(@NonNull @ContentPricing String priceType,
                 @Nullable String priceValue) {
             mBuilderPriceType = checkNotNull(priceType);
             mBuilderPriceValue = priceValue;
@@ -1028,7 +1029,7 @@
          * @param contentStatus The status value for this content. Must be one of the predefined
          *            content status values (see the <code>CONTENT_STATUS_*</code> constants).
          */
-        public Builder setStatus(@ContentStatus int contentStatus) {
+        public @NonNull Builder setStatus(@ContentStatus int contentStatus) {
             mBuilderStatus = contentStatus;
             return this;
         }
@@ -1040,7 +1041,7 @@
          *            tag must be one of the predefined maturity rating tags (see the <code>
          *            CONTENT_MATURITY_*</code> constants).
          */
-        public Builder setMaturityRating(@ContentMaturity String maturityRating) {
+        public @NonNull Builder setMaturityRating(@NonNull @ContentMaturity String maturityRating) {
             mBuilderMaturityRating = checkNotNull(maturityRating);
             return this;
         }
@@ -1050,7 +1051,7 @@
          *
          * @param length The running time, in seconds, of the content.
          */
-        public Builder setRunningTime(long length) {
+        public @NonNull Builder setRunningTime(long length) {
             if (length < 0) {
                 throw new IllegalArgumentException();
             }
@@ -1062,7 +1063,7 @@
          * Combine all of the options that have been set and return a new
          * {@link ContentRecommendation} object.
          */
-        public ContentRecommendation build() {
+        public @NonNull ContentRecommendation build() {
             return new ContentRecommendation(this);
         }
     }
@@ -1078,7 +1079,7 @@
      * @return A {@link android.app.Notification Notification} containing the stored recommendation
      *         data.
      */
-    public Notification getNotificationObject(Context context) {
+    public @NonNull Notification getNotificationObject(@NonNull Context context) {
         Notification.Builder builder = new Notification.Builder(context);
         RecommendationExtender recExtender = new RecommendationExtender();
 
@@ -1142,8 +1143,7 @@
         recExtender.setRunningTime(mRunningTime);
 
         builder.extend(recExtender);
-        Notification notif = builder.build();
-        return notif;
+        return builder.build();
     }
 
     /**
diff --git a/recommendation/recommendation/src/main/java/androidx/recommendation/app/RecommendationExtender.java b/recommendation/recommendation/src/main/java/androidx/recommendation/app/RecommendationExtender.java
index 2935fe0..0ff842e 100644
--- a/recommendation/recommendation/src/main/java/androidx/recommendation/app/RecommendationExtender.java
+++ b/recommendation/recommendation/src/main/java/androidx/recommendation/app/RecommendationExtender.java
@@ -19,6 +19,9 @@
 import android.app.Notification;
 import android.os.Bundle;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 /**
  * <p>
  * Helper class to add content info extensions to notifications. To create a notification with
@@ -80,7 +83,7 @@
      *
      * @param notif The notification from which to copy options.
      */
-    public RecommendationExtender(Notification notif) {
+    public RecommendationExtender(@NonNull Notification notif) {
         Bundle contentBundle = notif.extras == null ?
                 null : notif.extras.getBundle(EXTRA_CONTENT_INFO_EXTENDER);
         if (contentBundle != null) {
@@ -137,7 +140,7 @@
      * @param types Array of predefined type tags (see the <code>CONTENT_TYPE_*</code> constants)
      *            that describe the content referred to by a notification.
      */
-    public RecommendationExtender setContentTypes(String[] types) {
+    public @NonNull RecommendationExtender setContentTypes(@Nullable String[] types) {
         mTypes = types;
         return this;
     }
@@ -151,7 +154,7 @@
      *         describe the content associated with the notification.
      * @see RecommendationExtender#setContentTypes
      */
-    public String[] getContentTypes() {
+    public @Nullable String[] getContentTypes() {
         return mTypes;
     }
 
@@ -162,7 +165,7 @@
      *         primary type for the content associated with the notification.
      * @see RecommendationExtender#setContentTypes
      */
-    public String getPrimaryContentType() {
+    public @Nullable String getPrimaryContentType() {
         if (mTypes == null || mTypes.length == 0) {
             return null;
         }
@@ -178,7 +181,7 @@
      * @param genres Array of genre string tags that describe the content referred to by a
      *            notification.
      */
-    public RecommendationExtender setGenres(String[] genres) {
+    public @NonNull RecommendationExtender setGenres(@Nullable String[] genres) {
         mGenres = genres;
         return this;
     }
@@ -190,7 +193,7 @@
      * @return An array of genre tags that describe the content associated with the notification.
      * @see RecommendationExtender#setGenres
      */
-    public String[] getGenres() {
+    public @Nullable String[] getGenres() {
         return mGenres;
     }
 
@@ -205,8 +208,9 @@
      *            locale and currency.
      * @return This object for method chaining.
      */
-    public RecommendationExtender setPricingInformation(
-            @ContentRecommendation.ContentPricing String priceType, String priceValue) {
+    public @NonNull RecommendationExtender setPricingInformation(
+            @Nullable @ContentRecommendation.ContentPricing String priceType,
+            @Nullable String priceValue) {
         mPricingType = priceType;
         mPricingValue = priceValue;
         return this;
@@ -219,7 +223,7 @@
      *         constants).
      * @see RecommendationExtender#setPricingInformation
      */
-    public String getPricingType() {
+    public @Nullable String getPricingType() {
         return mPricingType;
     }
 
@@ -232,7 +236,7 @@
      *         currency.
      * @see RecommendationExtender#setPricingInformation
      */
-    public String getPricingValue() {
+    public @Nullable String getPricingValue() {
         if (mPricingType == null) {
             return null;
         }
@@ -247,7 +251,7 @@
      * @param contentStatus The status value for this content. Must be one of the predefined content
      *            status values (see the <code>CONTENT_STATUS_*</code> constants).
      */
-    public RecommendationExtender setStatus(
+    public @NonNull RecommendationExtender setStatus(
             @ContentRecommendation.ContentStatus int contentStatus) {
         mContentStatus = contentStatus;
         return this;
@@ -273,8 +277,8 @@
      *            must be one of the predefined maturity rating tags (see the <code> CONTENT_MATURITY_*</code>
      *            constants).
      */
-    public RecommendationExtender setMaturityRating(
-            @ContentRecommendation.ContentMaturity String maturityRating) {
+    public @NonNull RecommendationExtender setMaturityRating(
+            @Nullable @ContentRecommendation.ContentMaturity String maturityRating) {
         mMaturityRating = maturityRating;
         return this;
     }
@@ -286,7 +290,7 @@
      *         the <code>CONTENT_MATURITY_*</code> constants).
      * @see RecommendationExtender#setMaturityRating
      */
-    public String getMaturityRating() {
+    public @Nullable String getMaturityRating() {
         return mMaturityRating;
     }
 
@@ -295,7 +299,7 @@
      *
      * @param length The runing time, in seconds, of the content associated with the notification.
      */
-    public RecommendationExtender setRunningTime(long length) {
+    public @NonNull RecommendationExtender setRunningTime(long length) {
         if (length < 0) {
             throw new IllegalArgumentException("Invalid value for Running Time");
         }
diff --git a/recyclerview/recyclerview-selection/lint-baseline.xml b/recyclerview/recyclerview-selection/lint-baseline.xml
deleted file mode 100644
index d09277b..0000000
--- a/recyclerview/recyclerview-selection/lint-baseline.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    @MainThread"
-        errorLine2="    ^">
-        <location
-            file="src/main/java/androidx/recyclerview/selection/OperationMonitor.java"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    @MainThread"
-        errorLine2="    ^">
-        <location
-            file="src/main/java/androidx/recyclerview/selection/OperationMonitor.java"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    /** @hide */"
-        errorLine2="    ^">
-        <location
-            file="src/main/java/androidx/recyclerview/selection/OperationMonitor.java"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    /** @hide */"
-        errorLine2="    ^">
-        <location
-            file="src/main/java/androidx/recyclerview/selection/OperationMonitor.java"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    /**"
-        errorLine2="    ^">
-        <location
-            file="src/main/java/androidx/recyclerview/selection/OperationMonitor.java"/>
-    </issue>
-
-    <issue
-        id="LambdaLast"
-        message="Functional interface parameters (such as parameter 1, &quot;keys&quot;, in androidx.recyclerview.selection.SelectionTracker.setItemsSelected) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
-        errorLine1="    public abstract boolean setItemsSelected(@NonNull Iterable&lt;K> keys, boolean selected);"
-        errorLine2="                                                                        ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/recyclerview/selection/SelectionTracker.java"/>
-    </issue>
-
-</issues>
diff --git a/recyclerview/recyclerview/api/1.3.0-beta01.txt b/recyclerview/recyclerview/api/1.3.0-beta01.txt
new file mode 100644
index 0000000..b4c70ae
--- /dev/null
+++ b/recyclerview/recyclerview/api/1.3.0-beta01.txt
@@ -0,0 +1,1092 @@
+// Signature format: 4.0
+package androidx.recyclerview.widget {
+
+  public final class AdapterListUpdateCallback implements androidx.recyclerview.widget.ListUpdateCallback {
+    ctor public AdapterListUpdateCallback(androidx.recyclerview.widget.RecyclerView.Adapter);
+    method public void onChanged(int, int, Object?);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public final class AsyncDifferConfig<T> {
+    method public java.util.concurrent.Executor getBackgroundThreadExecutor();
+    method public androidx.recyclerview.widget.DiffUtil.ItemCallback<T!> getDiffCallback();
+  }
+
+  public static final class AsyncDifferConfig.Builder<T> {
+    ctor public AsyncDifferConfig.Builder(androidx.recyclerview.widget.DiffUtil.ItemCallback<T!>);
+    method public androidx.recyclerview.widget.AsyncDifferConfig<T!> build();
+    method public androidx.recyclerview.widget.AsyncDifferConfig.Builder<T!> setBackgroundThreadExecutor(java.util.concurrent.Executor?);
+  }
+
+  public class AsyncListDiffer<T> {
+    ctor public AsyncListDiffer(androidx.recyclerview.widget.RecyclerView.Adapter, androidx.recyclerview.widget.DiffUtil.ItemCallback<T!>);
+    ctor public AsyncListDiffer(androidx.recyclerview.widget.ListUpdateCallback, androidx.recyclerview.widget.AsyncDifferConfig<T!>);
+    method public void addListListener(androidx.recyclerview.widget.AsyncListDiffer.ListListener<T!>);
+    method public java.util.List<T!> getCurrentList();
+    method public void removeListListener(androidx.recyclerview.widget.AsyncListDiffer.ListListener<T!>);
+    method public void submitList(java.util.List<T!>?);
+    method public void submitList(java.util.List<T!>?, Runnable?);
+  }
+
+  public static interface AsyncListDiffer.ListListener<T> {
+    method public void onCurrentListChanged(java.util.List<T!>, java.util.List<T!>);
+  }
+
+  public class AsyncListUtil<T> {
+    ctor public AsyncListUtil(Class<T!>, int, androidx.recyclerview.widget.AsyncListUtil.DataCallback<T!>, androidx.recyclerview.widget.AsyncListUtil.ViewCallback);
+    method public T? getItem(int);
+    method public int getItemCount();
+    method public void onRangeChanged();
+    method public void refresh();
+  }
+
+  public abstract static class AsyncListUtil.DataCallback<T> {
+    ctor public AsyncListUtil.DataCallback();
+    method @WorkerThread public abstract void fillData(T![], int, int);
+    method @WorkerThread public int getMaxCachedTiles();
+    method @WorkerThread public void recycleData(T![], int);
+    method @WorkerThread public abstract int refreshData();
+  }
+
+  public abstract static class AsyncListUtil.ViewCallback {
+    ctor public AsyncListUtil.ViewCallback();
+    method @UiThread public void extendRangeInto(int[], int[], int);
+    method @UiThread public abstract void getItemRangeInto(int[]);
+    method @UiThread public abstract void onDataRefresh();
+    method @UiThread public abstract void onItemLoaded(int);
+    field public static final int HINT_SCROLL_ASC = 2; // 0x2
+    field public static final int HINT_SCROLL_DESC = 1; // 0x1
+    field public static final int HINT_SCROLL_NONE = 0; // 0x0
+  }
+
+  public class BatchingListUpdateCallback implements androidx.recyclerview.widget.ListUpdateCallback {
+    ctor public BatchingListUpdateCallback(androidx.recyclerview.widget.ListUpdateCallback);
+    method public void dispatchLastEvent();
+    method public void onChanged(int, int, Object?);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public final class ConcatAdapter extends androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder> {
+    ctor @java.lang.SafeVarargs public ConcatAdapter(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>!...);
+    ctor @java.lang.SafeVarargs public ConcatAdapter(androidx.recyclerview.widget.ConcatAdapter.Config, androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>!...);
+    ctor public ConcatAdapter(java.util.List<? extends androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>>);
+    ctor public ConcatAdapter(androidx.recyclerview.widget.ConcatAdapter.Config, java.util.List<? extends androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>>);
+    method public boolean addAdapter(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>);
+    method public boolean addAdapter(int, androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>);
+    method public java.util.List<? extends androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>> getAdapters();
+    method public int getItemCount();
+    method public android.util.Pair<androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>!,java.lang.Integer!> getWrappedAdapterAndPosition(int);
+    method public void onBindViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method public boolean onFailedToRecycleView(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onViewAttachedToWindow(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onViewDetachedFromWindow(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onViewRecycled(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean removeAdapter(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>);
+  }
+
+  public static final class ConcatAdapter.Config {
+    field public static final androidx.recyclerview.widget.ConcatAdapter.Config DEFAULT;
+    field public final boolean isolateViewTypes;
+    field public final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode stableIdMode;
+  }
+
+  public static final class ConcatAdapter.Config.Builder {
+    ctor public ConcatAdapter.Config.Builder();
+    method public androidx.recyclerview.widget.ConcatAdapter.Config build();
+    method public androidx.recyclerview.widget.ConcatAdapter.Config.Builder setIsolateViewTypes(boolean);
+    method public androidx.recyclerview.widget.ConcatAdapter.Config.Builder setStableIdMode(androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode);
+  }
+
+  public enum ConcatAdapter.Config.StableIdMode {
+    enum_constant public static final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode ISOLATED_STABLE_IDS;
+    enum_constant public static final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode NO_STABLE_IDS;
+    enum_constant public static final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode SHARED_STABLE_IDS;
+  }
+
+  public class DefaultItemAnimator extends androidx.recyclerview.widget.SimpleItemAnimator {
+    ctor public DefaultItemAnimator();
+    method public boolean animateAdd(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder?, int, int, int, int);
+    method public boolean animateMove(androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateRemove(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void endAnimation(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void endAnimations();
+    method public boolean isRunning();
+    method public void runPendingAnimations();
+  }
+
+  public class DiffUtil {
+    method public static androidx.recyclerview.widget.DiffUtil.DiffResult calculateDiff(androidx.recyclerview.widget.DiffUtil.Callback);
+    method public static androidx.recyclerview.widget.DiffUtil.DiffResult calculateDiff(androidx.recyclerview.widget.DiffUtil.Callback, boolean);
+  }
+
+  public abstract static class DiffUtil.Callback {
+    ctor public DiffUtil.Callback();
+    method public abstract boolean areContentsTheSame(int, int);
+    method public abstract boolean areItemsTheSame(int, int);
+    method public Object? getChangePayload(int, int);
+    method public abstract int getNewListSize();
+    method public abstract int getOldListSize();
+  }
+
+  public static class DiffUtil.DiffResult {
+    method public int convertNewPositionToOld(@IntRange(from=0) int);
+    method public int convertOldPositionToNew(@IntRange(from=0) int);
+    method public void dispatchUpdatesTo(androidx.recyclerview.widget.RecyclerView.Adapter);
+    method public void dispatchUpdatesTo(androidx.recyclerview.widget.ListUpdateCallback);
+    field public static final int NO_POSITION = -1; // 0xffffffff
+  }
+
+  public abstract static class DiffUtil.ItemCallback<T> {
+    ctor public DiffUtil.ItemCallback();
+    method public abstract boolean areContentsTheSame(T, T);
+    method public abstract boolean areItemsTheSame(T, T);
+    method public Object? getChangePayload(T, T);
+  }
+
+  public class DividerItemDecoration extends androidx.recyclerview.widget.RecyclerView.ItemDecoration {
+    ctor public DividerItemDecoration(android.content.Context, int);
+    method public android.graphics.drawable.Drawable? getDrawable();
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void setOrientation(int);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public class GridLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
+    ctor public GridLayoutManager(android.content.Context!, android.util.AttributeSet!, int, int);
+    ctor public GridLayoutManager(android.content.Context!, int);
+    ctor public GridLayoutManager(android.content.Context!, int, int, boolean);
+    method public int getSpanCount();
+    method public androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup! getSpanSizeLookup();
+    method public boolean isUsingSpansToEstimateScrollbarDimensions();
+    method public void setSpanCount(int);
+    method public void setSpanSizeLookup(androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup!);
+    method public void setUsingSpansToEstimateScrollbarDimensions(boolean);
+    field public static final int DEFAULT_SPAN_COUNT = -1; // 0xffffffff
+  }
+
+  public static final class GridLayoutManager.DefaultSpanSizeLookup extends androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.DefaultSpanSizeLookup();
+    method public int getSpanSize(int);
+  }
+
+  public static class GridLayoutManager.LayoutParams extends androidx.recyclerview.widget.RecyclerView.LayoutParams {
+    ctor public GridLayoutManager.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public GridLayoutManager.LayoutParams(int, int);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams!);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams!);
+    ctor public GridLayoutManager.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public int getSpanIndex();
+    method public int getSpanSize();
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+  public abstract static class GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.SpanSizeLookup();
+    method public int getSpanGroupIndex(int, int);
+    method public int getSpanIndex(int, int);
+    method public abstract int getSpanSize(int);
+    method public void invalidateSpanGroupIndexCache();
+    method public void invalidateSpanIndexCache();
+    method public boolean isSpanGroupIndexCacheEnabled();
+    method public boolean isSpanIndexCacheEnabled();
+    method public void setSpanGroupIndexCacheEnabled(boolean);
+    method public void setSpanIndexCacheEnabled(boolean);
+  }
+
+  public class ItemTouchHelper extends androidx.recyclerview.widget.RecyclerView.ItemDecoration implements androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener {
+    ctor public ItemTouchHelper(androidx.recyclerview.widget.ItemTouchHelper.Callback);
+    method public void attachToRecyclerView(androidx.recyclerview.widget.RecyclerView?);
+    method public void onChildViewAttachedToWindow(android.view.View);
+    method public void onChildViewDetachedFromWindow(android.view.View);
+    method public void startDrag(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void startSwipe(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    field public static final int ACTION_STATE_DRAG = 2; // 0x2
+    field public static final int ACTION_STATE_IDLE = 0; // 0x0
+    field public static final int ACTION_STATE_SWIPE = 1; // 0x1
+    field public static final int ANIMATION_TYPE_DRAG = 8; // 0x8
+    field public static final int ANIMATION_TYPE_SWIPE_CANCEL = 4; // 0x4
+    field public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 2; // 0x2
+    field public static final int DOWN = 2; // 0x2
+    field public static final int END = 32; // 0x20
+    field public static final int LEFT = 4; // 0x4
+    field public static final int RIGHT = 8; // 0x8
+    field public static final int START = 16; // 0x10
+    field public static final int UP = 1; // 0x1
+  }
+
+  public abstract static class ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.Callback();
+    method public boolean canDropOver(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? chooseDropTarget(androidx.recyclerview.widget.RecyclerView.ViewHolder, java.util.List<androidx.recyclerview.widget.RecyclerView.ViewHolder!>, int, int);
+    method public void clearView(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public int convertToAbsoluteDirection(int, int);
+    method public static int convertToRelativeDirection(int, int);
+    method public long getAnimationDuration(androidx.recyclerview.widget.RecyclerView, int, float, float);
+    method public int getBoundingBoxMargin();
+    method public static androidx.recyclerview.widget.ItemTouchUIUtil getDefaultUIUtil();
+    method public float getMoveThreshold(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public abstract int getMovementFlags(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public float getSwipeEscapeVelocity(float);
+    method public float getSwipeThreshold(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public float getSwipeVelocityThreshold(float);
+    method public int interpolateOutOfBoundsScroll(androidx.recyclerview.widget.RecyclerView, int, int, int, long);
+    method public boolean isItemViewSwipeEnabled();
+    method public boolean isLongPressDragEnabled();
+    method public static int makeFlag(int, int);
+    method public static int makeMovementFlags(int, int);
+    method public void onChildDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public void onChildDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public abstract boolean onMove(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onMoved(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int);
+    method public void onSelectedChanged(androidx.recyclerview.widget.RecyclerView.ViewHolder?, int);
+    method public abstract void onSwiped(androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
+    field public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200; // 0xc8
+    field public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250; // 0xfa
+  }
+
+  public abstract static class ItemTouchHelper.SimpleCallback extends androidx.recyclerview.widget.ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.SimpleCallback(int, int);
+    method public int getDragDirs(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public int getMovementFlags(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public int getSwipeDirs(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void setDefaultDragDirs(int);
+    method public void setDefaultSwipeDirs(int);
+  }
+
+  public static interface ItemTouchHelper.ViewDropHandler {
+    method public void prepareForDrop(android.view.View, android.view.View, int, int);
+  }
+
+  public interface ItemTouchUIUtil {
+    method public void clearView(android.view.View);
+    method public void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public void onSelected(android.view.View);
+  }
+
+  public class LinearLayoutManager extends androidx.recyclerview.widget.RecyclerView.LayoutManager implements androidx.recyclerview.widget.ItemTouchHelper.ViewDropHandler androidx.recyclerview.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
+    ctor public LinearLayoutManager(android.content.Context);
+    ctor public LinearLayoutManager(android.content.Context, int, boolean);
+    ctor public LinearLayoutManager(android.content.Context, android.util.AttributeSet?, int, int);
+    method protected void calculateExtraLayoutSpace(androidx.recyclerview.widget.RecyclerView.State, int[]);
+    method public android.graphics.PointF? computeScrollVectorForPosition(int);
+    method public int findFirstCompletelyVisibleItemPosition();
+    method public int findFirstVisibleItemPosition();
+    method public int findLastCompletelyVisibleItemPosition();
+    method public int findLastVisibleItemPosition();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method @Deprecated protected int getExtraLayoutSpace(androidx.recyclerview.widget.RecyclerView.State!);
+    method public int getInitialPrefetchItemCount();
+    method public int getOrientation();
+    method public boolean getRecycleChildrenOnDetach();
+    method public boolean getReverseLayout();
+    method public boolean getStackFromEnd();
+    method protected boolean isLayoutRTL();
+    method public boolean isSmoothScrollbarEnabled();
+    method public void prepareForDrop(android.view.View, android.view.View, int, int);
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setInitialPrefetchItemCount(int);
+    method public void setOrientation(int);
+    method public void setRecycleChildrenOnDetach(boolean);
+    method public void setReverseLayout(boolean);
+    method public void setSmoothScrollbarEnabled(boolean);
+    method public void setStackFromEnd(boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_OFFSET = -2147483648; // 0x80000000
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  protected static class LinearLayoutManager.LayoutChunkResult {
+    ctor protected LinearLayoutManager.LayoutChunkResult();
+    field public int mConsumed;
+    field public boolean mFinished;
+    field public boolean mFocusable;
+    field public boolean mIgnoreConsumed;
+  }
+
+  public class LinearSmoothScroller extends androidx.recyclerview.widget.RecyclerView.SmoothScroller {
+    ctor public LinearSmoothScroller(android.content.Context);
+    method public int calculateDtToFit(int, int, int, int, int);
+    method public int calculateDxToMakeVisible(android.view.View, int);
+    method public int calculateDyToMakeVisible(android.view.View, int);
+    method protected float calculateSpeedPerPixel(android.util.DisplayMetrics);
+    method protected int calculateTimeForDeceleration(int);
+    method protected int calculateTimeForScrolling(int);
+    method protected int getHorizontalSnapPreference();
+    method protected int getVerticalSnapPreference();
+    method protected void onSeekTargetStep(int, int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method protected void onStart();
+    method protected void onStop();
+    method protected void onTargetFound(android.view.View, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method protected void updateActionForInterimTarget(androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    field public static final int SNAP_TO_ANY = 0; // 0x0
+    field public static final int SNAP_TO_END = 1; // 0x1
+    field public static final int SNAP_TO_START = -1; // 0xffffffff
+    field protected final android.view.animation.DecelerateInterpolator! mDecelerateInterpolator;
+    field protected int mInterimTargetDx;
+    field protected int mInterimTargetDy;
+    field protected final android.view.animation.LinearInterpolator! mLinearInterpolator;
+    field protected android.graphics.PointF? mTargetVector;
+  }
+
+  public class LinearSnapHelper extends androidx.recyclerview.widget.SnapHelper {
+    ctor public LinearSnapHelper();
+    method public int[]! calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
+    method public android.view.View! findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager!);
+    method public int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager!, int, int);
+  }
+
+  public abstract class ListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
+    ctor protected ListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T!>);
+    ctor protected ListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T!>);
+    method public java.util.List<T!> getCurrentList();
+    method protected T! getItem(int);
+    method public int getItemCount();
+    method public void onCurrentListChanged(java.util.List<T!>, java.util.List<T!>);
+    method public void submitList(java.util.List<T!>?);
+    method public void submitList(java.util.List<T!>?, Runnable?);
+  }
+
+  public interface ListUpdateCallback {
+    method public void onChanged(int, int, Object?);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public abstract class OrientationHelper {
+    method public static androidx.recyclerview.widget.OrientationHelper! createHorizontalHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager!);
+    method public static androidx.recyclerview.widget.OrientationHelper! createOrientationHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager!, int);
+    method public static androidx.recyclerview.widget.OrientationHelper! createVerticalHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager!);
+    method public abstract int getDecoratedEnd(android.view.View!);
+    method public abstract int getDecoratedMeasurement(android.view.View!);
+    method public abstract int getDecoratedMeasurementInOther(android.view.View!);
+    method public abstract int getDecoratedStart(android.view.View!);
+    method public abstract int getEnd();
+    method public abstract int getEndAfterPadding();
+    method public abstract int getEndPadding();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutManager! getLayoutManager();
+    method public abstract int getMode();
+    method public abstract int getModeInOther();
+    method public abstract int getStartAfterPadding();
+    method public abstract int getTotalSpace();
+    method public int getTotalSpaceChange();
+    method public abstract int getTransformedEndWithDecoration(android.view.View!);
+    method public abstract int getTransformedStartWithDecoration(android.view.View!);
+    method public abstract void offsetChild(android.view.View!, int);
+    method public abstract void offsetChildren(int);
+    method public void onLayoutComplete();
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+    field protected final androidx.recyclerview.widget.RecyclerView.LayoutManager! mLayoutManager;
+  }
+
+  public class PagerSnapHelper extends androidx.recyclerview.widget.SnapHelper {
+    ctor public PagerSnapHelper();
+    method public int[]? calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
+    method public android.view.View? findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method public int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager, int, int);
+  }
+
+  public class RecyclerView extends android.view.ViewGroup implements androidx.core.view.NestedScrollingChild2 androidx.core.view.NestedScrollingChild3 androidx.core.view.ScrollingView {
+    ctor public RecyclerView(android.content.Context);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet?);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet?, int);
+    method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration, int);
+    method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
+    method public void addOnChildAttachStateChangeListener(androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void addOnItemTouchListener(androidx.recyclerview.widget.RecyclerView.OnItemTouchListener);
+    method public void addOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener);
+    method public void addRecyclerListener(androidx.recyclerview.widget.RecyclerView.RecyclerListener);
+    method public void clearOnChildAttachStateChangeListeners();
+    method public void clearOnScrollListeners();
+    method public int computeHorizontalScrollExtent();
+    method public int computeHorizontalScrollOffset();
+    method public int computeHorizontalScrollRange();
+    method public int computeVerticalScrollExtent();
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
+    method public boolean dispatchNestedPreScroll(int, int, int[]!, int[]!, int);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]!, int);
+    method public final void dispatchNestedScroll(int, int, int, int, int[]!, int, int[]);
+    method public boolean drawChild(android.graphics.Canvas!, android.view.View!, long);
+    method public android.view.View? findChildViewUnder(float, float);
+    method public android.view.View? findContainingItemView(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? findContainingViewHolder(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? findViewHolderForAdapterPosition(int);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder! findViewHolderForItemId(long);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? findViewHolderForLayoutPosition(int);
+    method @Deprecated public androidx.recyclerview.widget.RecyclerView.ViewHolder? findViewHolderForPosition(int);
+    method public boolean fling(int, int);
+    method public androidx.recyclerview.widget.RecyclerView.Adapter? getAdapter();
+    method public int getChildAdapterPosition(android.view.View);
+    method public long getChildItemId(android.view.View);
+    method public int getChildLayoutPosition(android.view.View);
+    method @Deprecated public int getChildPosition(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder! getChildViewHolder(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate? getCompatAccessibilityDelegate();
+    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
+    method public androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory getEdgeEffectFactory();
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator? getItemAnimator();
+    method public androidx.recyclerview.widget.RecyclerView.ItemDecoration getItemDecorationAt(int);
+    method public int getItemDecorationCount();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutManager? getLayoutManager();
+    method public int getMaxFlingVelocity();
+    method public int getMinFlingVelocity();
+    method public androidx.recyclerview.widget.RecyclerView.OnFlingListener? getOnFlingListener();
+    method public boolean getPreserveFocusAfterLayout();
+    method public androidx.recyclerview.widget.RecyclerView.RecycledViewPool getRecycledViewPool();
+    method public int getScrollState();
+    method public boolean hasFixedSize();
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean hasPendingAdapterUpdates();
+    method public void invalidateItemDecorations();
+    method public boolean isAnimating();
+    method public boolean isComputingLayout();
+    method @Deprecated public boolean isLayoutFrozen();
+    method public final boolean isLayoutSuppressed();
+    method public void nestedScrollBy(int, int);
+    method public void offsetChildrenHorizontal(@Px int);
+    method public void offsetChildrenVertical(@Px int);
+    method public void onChildAttachedToWindow(android.view.View);
+    method public void onChildDetachedFromWindow(android.view.View);
+    method public void onDraw(android.graphics.Canvas!);
+    method public void onScrollStateChanged(int);
+    method public void onScrolled(@Px int, @Px int);
+    method public void removeItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
+    method public void removeItemDecorationAt(int);
+    method public void removeOnChildAttachStateChangeListener(androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void removeOnItemTouchListener(androidx.recyclerview.widget.RecyclerView.OnItemTouchListener);
+    method public void removeOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener);
+    method public void removeRecyclerListener(androidx.recyclerview.widget.RecyclerView.RecyclerListener);
+    method public void scrollToPosition(int);
+    method public void setAccessibilityDelegateCompat(androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate?);
+    method public void setAdapter(androidx.recyclerview.widget.RecyclerView.Adapter?);
+    method public void setChildDrawingOrderCallback(androidx.recyclerview.widget.RecyclerView.ChildDrawingOrderCallback?);
+    method public void setEdgeEffectFactory(androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory);
+    method public void setHasFixedSize(boolean);
+    method public void setItemAnimator(androidx.recyclerview.widget.RecyclerView.ItemAnimator?);
+    method public void setItemViewCacheSize(int);
+    method @Deprecated public void setLayoutFrozen(boolean);
+    method public void setLayoutManager(androidx.recyclerview.widget.RecyclerView.LayoutManager?);
+    method @Deprecated public void setLayoutTransition(android.animation.LayoutTransition!);
+    method public void setOnFlingListener(androidx.recyclerview.widget.RecyclerView.OnFlingListener?);
+    method @Deprecated public void setOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener?);
+    method public void setPreserveFocusAfterLayout(boolean);
+    method public void setRecycledViewPool(androidx.recyclerview.widget.RecyclerView.RecycledViewPool?);
+    method @Deprecated public void setRecyclerListener(androidx.recyclerview.widget.RecyclerView.RecyclerListener?);
+    method public void setScrollingTouchSlop(int);
+    method public void setViewCacheExtension(androidx.recyclerview.widget.RecyclerView.ViewCacheExtension?);
+    method public void smoothScrollBy(@Px int, @Px int);
+    method public void smoothScrollBy(@Px int, @Px int, android.view.animation.Interpolator?);
+    method public void smoothScrollBy(@Px int, @Px int, android.view.animation.Interpolator?, int);
+    method public void smoothScrollToPosition(int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll(int);
+    method public void stopScroll();
+    method public final void suppressLayout(boolean);
+    method public void swapAdapter(androidx.recyclerview.widget.RecyclerView.Adapter?, boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_TYPE = -1; // 0xffffffff
+    field public static final long NO_ID = -1L; // 0xffffffffffffffffL
+    field public static final int NO_POSITION = -1; // 0xffffffff
+    field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
+    field public static final int SCROLL_STATE_IDLE = 0; // 0x0
+    field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
+    field public static final int TOUCH_SLOP_DEFAULT = 0; // 0x0
+    field public static final int TOUCH_SLOP_PAGING = 1; // 0x1
+    field public static final int UNDEFINED_DURATION = -2147483648; // 0x80000000
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public abstract static class RecyclerView.Adapter<VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> {
+    ctor public RecyclerView.Adapter();
+    method public final void bindViewHolder(VH, int);
+    method public final VH createViewHolder(android.view.ViewGroup, int);
+    method public int findRelativeAdapterPositionIn(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>, androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
+    method public abstract int getItemCount();
+    method public long getItemId(int);
+    method public int getItemViewType(int);
+    method public final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy getStateRestorationPolicy();
+    method public final boolean hasObservers();
+    method public final boolean hasStableIds();
+    method public final void notifyDataSetChanged();
+    method public final void notifyItemChanged(int);
+    method public final void notifyItemChanged(int, Object?);
+    method public final void notifyItemInserted(int);
+    method public final void notifyItemMoved(int, int);
+    method public final void notifyItemRangeChanged(int, int);
+    method public final void notifyItemRangeChanged(int, int, Object?);
+    method public final void notifyItemRangeInserted(int, int);
+    method public final void notifyItemRangeRemoved(int, int);
+    method public final void notifyItemRemoved(int);
+    method public void onAttachedToRecyclerView(androidx.recyclerview.widget.RecyclerView);
+    method public abstract void onBindViewHolder(VH, int);
+    method public void onBindViewHolder(VH, int, java.util.List<java.lang.Object!>);
+    method public abstract VH onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onDetachedFromRecyclerView(androidx.recyclerview.widget.RecyclerView);
+    method public boolean onFailedToRecycleView(VH);
+    method public void onViewAttachedToWindow(VH);
+    method public void onViewDetachedFromWindow(VH);
+    method public void onViewRecycled(VH);
+    method public void registerAdapterDataObserver(androidx.recyclerview.widget.RecyclerView.AdapterDataObserver);
+    method public void setHasStableIds(boolean);
+    method public void setStateRestorationPolicy(androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy);
+    method public void unregisterAdapterDataObserver(androidx.recyclerview.widget.RecyclerView.AdapterDataObserver);
+  }
+
+  public enum RecyclerView.Adapter.StateRestorationPolicy {
+    enum_constant public static final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy ALLOW;
+    enum_constant public static final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy PREVENT;
+    enum_constant public static final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy PREVENT_WHEN_EMPTY;
+  }
+
+  public abstract static class RecyclerView.AdapterDataObserver {
+    ctor public RecyclerView.AdapterDataObserver();
+    method public void onChanged();
+    method public void onItemRangeChanged(int, int);
+    method public void onItemRangeChanged(int, int, Object?);
+    method public void onItemRangeInserted(int, int);
+    method public void onItemRangeMoved(int, int, int);
+    method public void onItemRangeRemoved(int, int);
+    method public void onStateRestorationPolicyChanged();
+  }
+
+  public static interface RecyclerView.ChildDrawingOrderCallback {
+    method public int onGetChildDrawingOrder(int, int);
+  }
+
+  public static class RecyclerView.EdgeEffectFactory {
+    ctor public RecyclerView.EdgeEffectFactory();
+    method protected android.widget.EdgeEffect createEdgeEffect(androidx.recyclerview.widget.RecyclerView, @androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.EdgeDirection int);
+    field public static final int DIRECTION_BOTTOM = 3; // 0x3
+    field public static final int DIRECTION_LEFT = 0; // 0x0
+    field public static final int DIRECTION_RIGHT = 2; // 0x2
+    field public static final int DIRECTION_TOP = 1; // 0x1
+  }
+
+  @IntDef({androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_LEFT, androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_TOP, androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_RIGHT, androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_BOTTOM}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RecyclerView.EdgeEffectFactory.EdgeDirection {
+  }
+
+  public abstract static class RecyclerView.ItemAnimator {
+    ctor public RecyclerView.ItemAnimator();
+    method public abstract boolean animateAppearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateDisappearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?);
+    method public abstract boolean animatePersistence(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean canReuseUpdatedViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean canReuseUpdatedViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder, java.util.List<java.lang.Object!>);
+    method public final void dispatchAnimationFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationStarted(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationsFinished();
+    method public abstract void endAnimation(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public abstract void endAnimations();
+    method public long getAddDuration();
+    method public long getChangeDuration();
+    method public long getMoveDuration();
+    method public long getRemoveDuration();
+    method public abstract boolean isRunning();
+    method public final boolean isRunning(androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemAnimatorFinishedListener?);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo obtainHolderInfo();
+    method public void onAnimationFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onAnimationStarted(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPostLayoutInformation(androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPreLayoutInformation(androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.ViewHolder, @androidx.recyclerview.widget.RecyclerView.ItemAnimator.AdapterChanges int, java.util.List<java.lang.Object!>);
+    method public abstract void runPendingAnimations();
+    method public void setAddDuration(long);
+    method public void setChangeDuration(long);
+    method public void setMoveDuration(long);
+    method public void setRemoveDuration(long);
+    field public static final int FLAG_APPEARED_IN_PRE_LAYOUT = 4096; // 0x1000
+    field public static final int FLAG_CHANGED = 2; // 0x2
+    field public static final int FLAG_INVALIDATED = 4; // 0x4
+    field public static final int FLAG_MOVED = 2048; // 0x800
+    field public static final int FLAG_REMOVED = 8; // 0x8
+  }
+
+  @IntDef(flag=true, value={androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_CHANGED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_REMOVED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_MOVED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_INVALIDATED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RecyclerView.ItemAnimator.AdapterChanges {
+  }
+
+  public static interface RecyclerView.ItemAnimator.ItemAnimatorFinishedListener {
+    method public void onAnimationsFinished();
+  }
+
+  public static class RecyclerView.ItemAnimator.ItemHolderInfo {
+    ctor public RecyclerView.ItemAnimator.ItemHolderInfo();
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(androidx.recyclerview.widget.RecyclerView.ViewHolder, @androidx.recyclerview.widget.RecyclerView.ItemAnimator.AdapterChanges int);
+    field public int bottom;
+    field @androidx.recyclerview.widget.RecyclerView.ItemAnimator.AdapterChanges public int changeFlags;
+    field public int left;
+    field public int right;
+    field public int top;
+  }
+
+  public abstract static class RecyclerView.ItemDecoration {
+    ctor public RecyclerView.ItemDecoration();
+    method @Deprecated public void getItemOffsets(android.graphics.Rect, int, androidx.recyclerview.widget.RecyclerView);
+    method public void getItemOffsets(android.graphics.Rect, android.view.View, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
+    method public void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
+    method @Deprecated public void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView);
+    method public void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
+    method @Deprecated public void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView);
+  }
+
+  public abstract static class RecyclerView.LayoutManager {
+    ctor public RecyclerView.LayoutManager();
+    method public void addDisappearingView(android.view.View!);
+    method public void addDisappearingView(android.view.View!, int);
+    method public void addView(android.view.View!);
+    method public void addView(android.view.View!, int);
+    method public void assertInLayoutOrScroll(String!);
+    method public void assertNotInLayoutOrScroll(String?);
+    method public void attachView(android.view.View, int, androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public void attachView(android.view.View, int);
+    method public void attachView(android.view.View);
+    method public void calculateItemDecorationsForChild(android.view.View, android.graphics.Rect);
+    method public boolean canScrollHorizontally();
+    method public boolean canScrollVertically();
+    method public boolean checkLayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public static int chooseSize(int, int, int);
+    method public void collectAdjacentPrefetchPositions(int, int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
+    method public void collectInitialPrefetchPositions(int, androidx.recyclerview.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
+    method public int computeHorizontalScrollExtent(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeHorizontalScrollOffset(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeHorizontalScrollRange(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeVerticalScrollExtent(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeVerticalScrollOffset(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeVerticalScrollRange(androidx.recyclerview.widget.RecyclerView.State);
+    method public void detachAndScrapAttachedViews(androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void detachAndScrapView(android.view.View, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void detachAndScrapViewAt(int, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void detachView(android.view.View);
+    method public void detachViewAt(int);
+    method public void endAnimation(android.view.View!);
+    method public android.view.View? findContainingItemView(android.view.View);
+    method public android.view.View? findViewByPosition(int);
+    method public abstract androidx.recyclerview.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams! generateLayoutParams(android.view.ViewGroup.LayoutParams!);
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams! generateLayoutParams(android.content.Context!, android.util.AttributeSet!);
+    method public int getBaseline();
+    method public int getBottomDecorationHeight(android.view.View);
+    method public android.view.View? getChildAt(int);
+    method public int getChildCount();
+    method @Deprecated public static int getChildMeasureSpec(int, int, int, boolean);
+    method public static int getChildMeasureSpec(int, int, int, int, boolean);
+    method public boolean getClipToPadding();
+    method public int getColumnCountForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public int getDecoratedBottom(android.view.View);
+    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
+    method public int getDecoratedLeft(android.view.View);
+    method public int getDecoratedMeasuredHeight(android.view.View);
+    method public int getDecoratedMeasuredWidth(android.view.View);
+    method public int getDecoratedRight(android.view.View);
+    method public int getDecoratedTop(android.view.View);
+    method public android.view.View? getFocusedChild();
+    method @Px public int getHeight();
+    method public int getHeightMode();
+    method public int getItemCount();
+    method public int getItemViewType(android.view.View);
+    method public int getLayoutDirection();
+    method public int getLeftDecorationWidth(android.view.View);
+    method @Px public int getMinimumHeight();
+    method @Px public int getMinimumWidth();
+    method @Px public int getPaddingBottom();
+    method @Px public int getPaddingEnd();
+    method @Px public int getPaddingLeft();
+    method @Px public int getPaddingRight();
+    method @Px public int getPaddingStart();
+    method @Px public int getPaddingTop();
+    method public int getPosition(android.view.View);
+    method public static androidx.recyclerview.widget.RecyclerView.LayoutManager.Properties! getProperties(android.content.Context, android.util.AttributeSet?, int, int);
+    method public int getRightDecorationWidth(android.view.View);
+    method public int getRowCountForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public int getSelectionModeForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public int getTopDecorationHeight(android.view.View);
+    method public void getTransformedBoundingBox(android.view.View, boolean, android.graphics.Rect);
+    method @Px public int getWidth();
+    method public int getWidthMode();
+    method public boolean hasFocus();
+    method public void ignoreView(android.view.View);
+    method public boolean isAttachedToWindow();
+    method public boolean isAutoMeasureEnabled();
+    method public boolean isFocused();
+    method public final boolean isItemPrefetchEnabled();
+    method public boolean isLayoutHierarchical(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public boolean isMeasurementCacheEnabled();
+    method public boolean isSmoothScrolling();
+    method public boolean isViewPartiallyVisible(android.view.View, boolean, boolean);
+    method public void layoutDecorated(android.view.View, int, int, int, int);
+    method public void layoutDecoratedWithMargins(android.view.View, int, int, int, int);
+    method public void measureChild(android.view.View, int, int);
+    method public void measureChildWithMargins(android.view.View, int, int);
+    method public void moveView(int, int);
+    method public void offsetChildrenHorizontal(@Px int);
+    method public void offsetChildrenVertical(@Px int);
+    method public void onAdapterChanged(androidx.recyclerview.widget.RecyclerView.Adapter?, androidx.recyclerview.widget.RecyclerView.Adapter?);
+    method public boolean onAddFocusables(androidx.recyclerview.widget.RecyclerView, java.util.ArrayList<android.view.View!>, int, int);
+    method @CallSuper public void onAttachedToWindow(androidx.recyclerview.widget.RecyclerView!);
+    method @Deprecated public void onDetachedFromWindow(androidx.recyclerview.widget.RecyclerView!);
+    method @CallSuper public void onDetachedFromWindow(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public android.view.View? onFocusSearchFailed(android.view.View, int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityEvent(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+    method public void onInitializeAccessibilityNodeInfoForItem(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+    method public android.view.View? onInterceptFocusSearch(android.view.View, int);
+    method public void onItemsAdded(androidx.recyclerview.widget.RecyclerView, int, int);
+    method public void onItemsChanged(androidx.recyclerview.widget.RecyclerView);
+    method public void onItemsMoved(androidx.recyclerview.widget.RecyclerView, int, int, int);
+    method public void onItemsRemoved(androidx.recyclerview.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(androidx.recyclerview.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(androidx.recyclerview.widget.RecyclerView, int, int, Object?);
+    method public void onLayoutChildren(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public void onLayoutCompleted(androidx.recyclerview.widget.RecyclerView.State);
+    method public void onMeasure(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, int, int);
+    method @Deprecated public boolean onRequestChildFocus(androidx.recyclerview.widget.RecyclerView, android.view.View, android.view.View?);
+    method public boolean onRequestChildFocus(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State, android.view.View, android.view.View?);
+    method public void onRestoreInstanceState(android.os.Parcelable);
+    method public android.os.Parcelable? onSaveInstanceState();
+    method public void onScrollStateChanged(int);
+    method public boolean performAccessibilityAction(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, int, android.os.Bundle?);
+    method public boolean performAccessibilityActionForItem(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.View, int, android.os.Bundle?);
+    method public void postOnAnimation(Runnable!);
+    method public void removeAllViews();
+    method public void removeAndRecycleAllViews(androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleView(android.view.View, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleViewAt(int, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public boolean removeCallbacks(Runnable!);
+    method public void removeDetachedView(android.view.View);
+    method public void removeView(android.view.View!);
+    method public void removeViewAt(int);
+    method public boolean requestChildRectangleOnScreen(androidx.recyclerview.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean);
+    method public boolean requestChildRectangleOnScreen(androidx.recyclerview.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean, boolean);
+    method public void requestLayout();
+    method public void requestSimpleAnimationsInNextLayout();
+    method public int scrollHorizontallyBy(int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public void scrollToPosition(int);
+    method public int scrollVerticallyBy(int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method @Deprecated public void setAutoMeasureEnabled(boolean);
+    method public final void setItemPrefetchEnabled(boolean);
+    method public void setMeasuredDimension(android.graphics.Rect!, int, int);
+    method public void setMeasuredDimension(int, int);
+    method public void setMeasurementCacheEnabled(boolean);
+    method public void smoothScrollToPosition(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State, int);
+    method public void startSmoothScroll(androidx.recyclerview.widget.RecyclerView.SmoothScroller!);
+    method public void stopIgnoringView(android.view.View);
+    method public boolean supportsPredictiveItemAnimations();
+  }
+
+  public static interface RecyclerView.LayoutManager.LayoutPrefetchRegistry {
+    method public void addPosition(int, int);
+  }
+
+  public static class RecyclerView.LayoutManager.Properties {
+    ctor public RecyclerView.LayoutManager.Properties();
+    field public int orientation;
+    field public boolean reverseLayout;
+    field public int spanCount;
+    field public boolean stackFromEnd;
+  }
+
+  public static class RecyclerView.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public RecyclerView.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public RecyclerView.LayoutParams(int, int);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.MarginLayoutParams!);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.LayoutParams!);
+    ctor public RecyclerView.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public int getAbsoluteAdapterPosition();
+    method public int getBindingAdapterPosition();
+    method @Deprecated public int getViewAdapterPosition();
+    method public int getViewLayoutPosition();
+    method @Deprecated public int getViewPosition();
+    method public boolean isItemChanged();
+    method public boolean isItemRemoved();
+    method public boolean isViewInvalid();
+    method public boolean viewNeedsUpdate();
+  }
+
+  public static interface RecyclerView.OnChildAttachStateChangeListener {
+    method public void onChildViewAttachedToWindow(android.view.View);
+    method public void onChildViewDetachedFromWindow(android.view.View);
+  }
+
+  public abstract static class RecyclerView.OnFlingListener {
+    ctor public RecyclerView.OnFlingListener();
+    method public abstract boolean onFling(int, int);
+  }
+
+  public static interface RecyclerView.OnItemTouchListener {
+    method public boolean onInterceptTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+    method public void onRequestDisallowInterceptTouchEvent(boolean);
+    method public void onTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public abstract static class RecyclerView.OnScrollListener {
+    ctor public RecyclerView.OnScrollListener();
+    method public void onScrollStateChanged(androidx.recyclerview.widget.RecyclerView, int);
+    method public void onScrolled(androidx.recyclerview.widget.RecyclerView, int, int);
+  }
+
+  public static class RecyclerView.RecycledViewPool {
+    ctor public RecyclerView.RecycledViewPool();
+    method public void clear();
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? getRecycledView(int);
+    method public int getRecycledViewCount(int);
+    method public void putRecycledView(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void setMaxRecycledViews(int, int);
+  }
+
+  public final class RecyclerView.Recycler {
+    ctor public RecyclerView.Recycler();
+    method public void bindViewToPosition(android.view.View, int);
+    method public void clear();
+    method public int convertPreLayoutPositionToPostLayout(int);
+    method public java.util.List<androidx.recyclerview.widget.RecyclerView.ViewHolder!> getScrapList();
+    method public android.view.View getViewForPosition(int);
+    method public void recycleView(android.view.View);
+    method public void setViewCacheSize(int);
+  }
+
+  public static interface RecyclerView.RecyclerListener {
+    method public void onViewRecycled(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+  }
+
+  public static class RecyclerView.SimpleOnItemTouchListener implements androidx.recyclerview.widget.RecyclerView.OnItemTouchListener {
+    ctor public RecyclerView.SimpleOnItemTouchListener();
+    method public boolean onInterceptTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+    method public void onRequestDisallowInterceptTouchEvent(boolean);
+    method public void onTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public abstract static class RecyclerView.SmoothScroller {
+    ctor public RecyclerView.SmoothScroller();
+    method public android.graphics.PointF? computeScrollVectorForPosition(int);
+    method public android.view.View! findViewByPosition(int);
+    method public int getChildCount();
+    method public int getChildPosition(android.view.View!);
+    method public androidx.recyclerview.widget.RecyclerView.LayoutManager? getLayoutManager();
+    method public int getTargetPosition();
+    method @Deprecated public void instantScrollToPosition(int);
+    method public boolean isPendingInitialRun();
+    method public boolean isRunning();
+    method protected void normalize(android.graphics.PointF);
+    method protected void onChildAttachedToWindow(android.view.View!);
+    method protected abstract void onSeekTargetStep(@Px int, @Px int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method protected abstract void onStart();
+    method protected abstract void onStop();
+    method protected abstract void onTargetFound(android.view.View, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method public void setTargetPosition(int);
+    method protected final void stop();
+  }
+
+  public static class RecyclerView.SmoothScroller.Action {
+    ctor public RecyclerView.SmoothScroller.Action(@Px int, @Px int);
+    ctor public RecyclerView.SmoothScroller.Action(@Px int, @Px int, int);
+    ctor public RecyclerView.SmoothScroller.Action(@Px int, @Px int, int, android.view.animation.Interpolator?);
+    method public int getDuration();
+    method @Px public int getDx();
+    method @Px public int getDy();
+    method public android.view.animation.Interpolator? getInterpolator();
+    method public void jumpTo(int);
+    method public void setDuration(int);
+    method public void setDx(@Px int);
+    method public void setDy(@Px int);
+    method public void setInterpolator(android.view.animation.Interpolator?);
+    method public void update(@Px int, @Px int, int, android.view.animation.Interpolator?);
+    field public static final int UNDEFINED_DURATION = -2147483648; // 0x80000000
+  }
+
+  public static interface RecyclerView.SmoothScroller.ScrollVectorProvider {
+    method public android.graphics.PointF? computeScrollVectorForPosition(int);
+  }
+
+  public static class RecyclerView.State {
+    ctor public RecyclerView.State();
+    method public boolean didStructureChange();
+    method public <T> T! get(int);
+    method public int getItemCount();
+    method public int getRemainingScrollHorizontal();
+    method public int getRemainingScrollVertical();
+    method public int getTargetScrollPosition();
+    method public boolean hasTargetScrollPosition();
+    method public boolean isMeasuring();
+    method public boolean isPreLayout();
+    method public void put(int, Object!);
+    method public void remove(int);
+    method public boolean willRunPredictiveAnimations();
+    method public boolean willRunSimpleAnimations();
+  }
+
+  public abstract static class RecyclerView.ViewCacheExtension {
+    ctor public RecyclerView.ViewCacheExtension();
+    method public abstract android.view.View? getViewForPositionAndType(androidx.recyclerview.widget.RecyclerView.Recycler, int, int);
+  }
+
+  public abstract static class RecyclerView.ViewHolder {
+    ctor public RecyclerView.ViewHolder(android.view.View);
+    method public final int getAbsoluteAdapterPosition();
+    method @Deprecated public final int getAdapterPosition();
+    method public final androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>? getBindingAdapter();
+    method public final int getBindingAdapterPosition();
+    method public final long getItemId();
+    method public final int getItemViewType();
+    method public final int getLayoutPosition();
+    method public final int getOldPosition();
+    method @Deprecated public final int getPosition();
+    method public final boolean isRecyclable();
+    method public final void setIsRecyclable(boolean);
+    field public final android.view.View itemView;
+  }
+
+  public class RecyclerViewAccessibilityDelegate extends androidx.core.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate(androidx.recyclerview.widget.RecyclerView);
+    method public androidx.core.view.AccessibilityDelegateCompat getItemDelegate();
+  }
+
+  public static class RecyclerViewAccessibilityDelegate.ItemDelegate extends androidx.core.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate.ItemDelegate(androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate);
+  }
+
+  public abstract class SimpleItemAnimator extends androidx.recyclerview.widget.RecyclerView.ItemAnimator {
+    ctor public SimpleItemAnimator();
+    method public abstract boolean animateAdd(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean animateAppearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder?, int, int, int, int);
+    method public boolean animateDisappearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?);
+    method public abstract boolean animateMove(androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animatePersistence(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateRemove(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAddFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchAddStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchChangeFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public final void dispatchChangeStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public final void dispatchMoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchMoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchRemoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchRemoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public boolean getSupportsChangeAnimations();
+    method public void onAddFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onAddStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onChangeFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public void onChangeStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public void onMoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onMoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onRemoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onRemoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void setSupportsChangeAnimations(boolean);
+  }
+
+  public abstract class SnapHelper extends androidx.recyclerview.widget.RecyclerView.OnFlingListener {
+    ctor public SnapHelper();
+    method public void attachToRecyclerView(androidx.recyclerview.widget.RecyclerView?) throws java.lang.IllegalStateException;
+    method public abstract int[]? calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
+    method public int[] calculateScrollDistance(int, int);
+    method protected androidx.recyclerview.widget.RecyclerView.SmoothScroller? createScroller(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method @Deprecated protected androidx.recyclerview.widget.LinearSmoothScroller? createSnapScroller(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method public abstract android.view.View? findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method public abstract int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager, int, int);
+    method public boolean onFling(int, int);
+  }
+
+  public class SortedList<T> {
+    ctor public SortedList(Class<T!>, androidx.recyclerview.widget.SortedList.Callback<T!>);
+    ctor public SortedList(Class<T!>, androidx.recyclerview.widget.SortedList.Callback<T!>, int);
+    method public int add(T!);
+    method public void addAll(T![], boolean);
+    method public void addAll(T!...);
+    method public void addAll(java.util.Collection<T!>);
+    method public void beginBatchedUpdates();
+    method public void clear();
+    method public void endBatchedUpdates();
+    method public T! get(int) throws java.lang.IndexOutOfBoundsException;
+    method public int indexOf(T!);
+    method public void recalculatePositionOfItemAt(int);
+    method public boolean remove(T!);
+    method public T! removeItemAt(int);
+    method public void replaceAll(T![], boolean);
+    method public void replaceAll(T!...);
+    method public void replaceAll(java.util.Collection<T!>);
+    method public int size();
+    method public void updateItemAt(int, T!);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static class SortedList.BatchedCallback<T2> extends androidx.recyclerview.widget.SortedList.Callback<T2> {
+    ctor public SortedList.BatchedCallback(androidx.recyclerview.widget.SortedList.Callback<T2!>);
+    method public boolean areContentsTheSame(T2!, T2!);
+    method public boolean areItemsTheSame(T2!, T2!);
+    method public int compare(T2!, T2!);
+    method public void dispatchLastEvent();
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public abstract static class SortedList.Callback<T2> implements java.util.Comparator<T2> androidx.recyclerview.widget.ListUpdateCallback {
+    ctor public SortedList.Callback();
+    method public abstract boolean areContentsTheSame(T2!, T2!);
+    method public abstract boolean areItemsTheSame(T2!, T2!);
+    method public abstract int compare(T2!, T2!);
+    method public Object? getChangePayload(T2!, T2!);
+    method public abstract void onChanged(int, int);
+    method public void onChanged(int, int, Object?);
+  }
+
+  public abstract class SortedListAdapterCallback<T2> extends androidx.recyclerview.widget.SortedList.Callback<T2> {
+    ctor public SortedListAdapterCallback(androidx.recyclerview.widget.RecyclerView.Adapter<?>);
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public class StaggeredGridLayoutManager extends androidx.recyclerview.widget.RecyclerView.LayoutManager implements androidx.recyclerview.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
+    ctor public StaggeredGridLayoutManager(android.content.Context!, android.util.AttributeSet!, int, int);
+    ctor public StaggeredGridLayoutManager(int, int);
+    method public android.graphics.PointF! computeScrollVectorForPosition(int);
+    method public int[]! findFirstCompletelyVisibleItemPositions(int[]!);
+    method public int[]! findFirstVisibleItemPositions(int[]!);
+    method public int[]! findLastCompletelyVisibleItemPositions(int[]!);
+    method public int[]! findLastVisibleItemPositions(int[]!);
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams! generateDefaultLayoutParams();
+    method public int getGapStrategy();
+    method public int getOrientation();
+    method public boolean getReverseLayout();
+    method public int getSpanCount();
+    method public void invalidateSpanAssignments();
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setGapStrategy(int);
+    method public void setOrientation(int);
+    method public void setReverseLayout(boolean);
+    method public void setSpanCount(int);
+    field @Deprecated public static final int GAP_HANDLING_LAZY = 1; // 0x1
+    field public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; // 0x2
+    field public static final int GAP_HANDLING_NONE = 0; // 0x0
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static class StaggeredGridLayoutManager.LayoutParams extends androidx.recyclerview.widget.RecyclerView.LayoutParams {
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public StaggeredGridLayoutManager.LayoutParams(int, int);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams!);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams!);
+    ctor public StaggeredGridLayoutManager.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public final int getSpanIndex();
+    method public boolean isFullSpan();
+    method public void setFullSpan(boolean);
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+}
+
diff --git a/recyclerview/recyclerview/api/public_plus_experimental_1.3.0-beta01.txt b/recyclerview/recyclerview/api/public_plus_experimental_1.3.0-beta01.txt
new file mode 100644
index 0000000..b4c70ae
--- /dev/null
+++ b/recyclerview/recyclerview/api/public_plus_experimental_1.3.0-beta01.txt
@@ -0,0 +1,1092 @@
+// Signature format: 4.0
+package androidx.recyclerview.widget {
+
+  public final class AdapterListUpdateCallback implements androidx.recyclerview.widget.ListUpdateCallback {
+    ctor public AdapterListUpdateCallback(androidx.recyclerview.widget.RecyclerView.Adapter);
+    method public void onChanged(int, int, Object?);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public final class AsyncDifferConfig<T> {
+    method public java.util.concurrent.Executor getBackgroundThreadExecutor();
+    method public androidx.recyclerview.widget.DiffUtil.ItemCallback<T!> getDiffCallback();
+  }
+
+  public static final class AsyncDifferConfig.Builder<T> {
+    ctor public AsyncDifferConfig.Builder(androidx.recyclerview.widget.DiffUtil.ItemCallback<T!>);
+    method public androidx.recyclerview.widget.AsyncDifferConfig<T!> build();
+    method public androidx.recyclerview.widget.AsyncDifferConfig.Builder<T!> setBackgroundThreadExecutor(java.util.concurrent.Executor?);
+  }
+
+  public class AsyncListDiffer<T> {
+    ctor public AsyncListDiffer(androidx.recyclerview.widget.RecyclerView.Adapter, androidx.recyclerview.widget.DiffUtil.ItemCallback<T!>);
+    ctor public AsyncListDiffer(androidx.recyclerview.widget.ListUpdateCallback, androidx.recyclerview.widget.AsyncDifferConfig<T!>);
+    method public void addListListener(androidx.recyclerview.widget.AsyncListDiffer.ListListener<T!>);
+    method public java.util.List<T!> getCurrentList();
+    method public void removeListListener(androidx.recyclerview.widget.AsyncListDiffer.ListListener<T!>);
+    method public void submitList(java.util.List<T!>?);
+    method public void submitList(java.util.List<T!>?, Runnable?);
+  }
+
+  public static interface AsyncListDiffer.ListListener<T> {
+    method public void onCurrentListChanged(java.util.List<T!>, java.util.List<T!>);
+  }
+
+  public class AsyncListUtil<T> {
+    ctor public AsyncListUtil(Class<T!>, int, androidx.recyclerview.widget.AsyncListUtil.DataCallback<T!>, androidx.recyclerview.widget.AsyncListUtil.ViewCallback);
+    method public T? getItem(int);
+    method public int getItemCount();
+    method public void onRangeChanged();
+    method public void refresh();
+  }
+
+  public abstract static class AsyncListUtil.DataCallback<T> {
+    ctor public AsyncListUtil.DataCallback();
+    method @WorkerThread public abstract void fillData(T![], int, int);
+    method @WorkerThread public int getMaxCachedTiles();
+    method @WorkerThread public void recycleData(T![], int);
+    method @WorkerThread public abstract int refreshData();
+  }
+
+  public abstract static class AsyncListUtil.ViewCallback {
+    ctor public AsyncListUtil.ViewCallback();
+    method @UiThread public void extendRangeInto(int[], int[], int);
+    method @UiThread public abstract void getItemRangeInto(int[]);
+    method @UiThread public abstract void onDataRefresh();
+    method @UiThread public abstract void onItemLoaded(int);
+    field public static final int HINT_SCROLL_ASC = 2; // 0x2
+    field public static final int HINT_SCROLL_DESC = 1; // 0x1
+    field public static final int HINT_SCROLL_NONE = 0; // 0x0
+  }
+
+  public class BatchingListUpdateCallback implements androidx.recyclerview.widget.ListUpdateCallback {
+    ctor public BatchingListUpdateCallback(androidx.recyclerview.widget.ListUpdateCallback);
+    method public void dispatchLastEvent();
+    method public void onChanged(int, int, Object?);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public final class ConcatAdapter extends androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder> {
+    ctor @java.lang.SafeVarargs public ConcatAdapter(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>!...);
+    ctor @java.lang.SafeVarargs public ConcatAdapter(androidx.recyclerview.widget.ConcatAdapter.Config, androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>!...);
+    ctor public ConcatAdapter(java.util.List<? extends androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>>);
+    ctor public ConcatAdapter(androidx.recyclerview.widget.ConcatAdapter.Config, java.util.List<? extends androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>>);
+    method public boolean addAdapter(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>);
+    method public boolean addAdapter(int, androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>);
+    method public java.util.List<? extends androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>> getAdapters();
+    method public int getItemCount();
+    method public android.util.Pair<androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>!,java.lang.Integer!> getWrappedAdapterAndPosition(int);
+    method public void onBindViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method public boolean onFailedToRecycleView(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onViewAttachedToWindow(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onViewDetachedFromWindow(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onViewRecycled(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean removeAdapter(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>);
+  }
+
+  public static final class ConcatAdapter.Config {
+    field public static final androidx.recyclerview.widget.ConcatAdapter.Config DEFAULT;
+    field public final boolean isolateViewTypes;
+    field public final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode stableIdMode;
+  }
+
+  public static final class ConcatAdapter.Config.Builder {
+    ctor public ConcatAdapter.Config.Builder();
+    method public androidx.recyclerview.widget.ConcatAdapter.Config build();
+    method public androidx.recyclerview.widget.ConcatAdapter.Config.Builder setIsolateViewTypes(boolean);
+    method public androidx.recyclerview.widget.ConcatAdapter.Config.Builder setStableIdMode(androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode);
+  }
+
+  public enum ConcatAdapter.Config.StableIdMode {
+    enum_constant public static final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode ISOLATED_STABLE_IDS;
+    enum_constant public static final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode NO_STABLE_IDS;
+    enum_constant public static final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode SHARED_STABLE_IDS;
+  }
+
+  public class DefaultItemAnimator extends androidx.recyclerview.widget.SimpleItemAnimator {
+    ctor public DefaultItemAnimator();
+    method public boolean animateAdd(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder?, int, int, int, int);
+    method public boolean animateMove(androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateRemove(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void endAnimation(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void endAnimations();
+    method public boolean isRunning();
+    method public void runPendingAnimations();
+  }
+
+  public class DiffUtil {
+    method public static androidx.recyclerview.widget.DiffUtil.DiffResult calculateDiff(androidx.recyclerview.widget.DiffUtil.Callback);
+    method public static androidx.recyclerview.widget.DiffUtil.DiffResult calculateDiff(androidx.recyclerview.widget.DiffUtil.Callback, boolean);
+  }
+
+  public abstract static class DiffUtil.Callback {
+    ctor public DiffUtil.Callback();
+    method public abstract boolean areContentsTheSame(int, int);
+    method public abstract boolean areItemsTheSame(int, int);
+    method public Object? getChangePayload(int, int);
+    method public abstract int getNewListSize();
+    method public abstract int getOldListSize();
+  }
+
+  public static class DiffUtil.DiffResult {
+    method public int convertNewPositionToOld(@IntRange(from=0) int);
+    method public int convertOldPositionToNew(@IntRange(from=0) int);
+    method public void dispatchUpdatesTo(androidx.recyclerview.widget.RecyclerView.Adapter);
+    method public void dispatchUpdatesTo(androidx.recyclerview.widget.ListUpdateCallback);
+    field public static final int NO_POSITION = -1; // 0xffffffff
+  }
+
+  public abstract static class DiffUtil.ItemCallback<T> {
+    ctor public DiffUtil.ItemCallback();
+    method public abstract boolean areContentsTheSame(T, T);
+    method public abstract boolean areItemsTheSame(T, T);
+    method public Object? getChangePayload(T, T);
+  }
+
+  public class DividerItemDecoration extends androidx.recyclerview.widget.RecyclerView.ItemDecoration {
+    ctor public DividerItemDecoration(android.content.Context, int);
+    method public android.graphics.drawable.Drawable? getDrawable();
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void setOrientation(int);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public class GridLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
+    ctor public GridLayoutManager(android.content.Context!, android.util.AttributeSet!, int, int);
+    ctor public GridLayoutManager(android.content.Context!, int);
+    ctor public GridLayoutManager(android.content.Context!, int, int, boolean);
+    method public int getSpanCount();
+    method public androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup! getSpanSizeLookup();
+    method public boolean isUsingSpansToEstimateScrollbarDimensions();
+    method public void setSpanCount(int);
+    method public void setSpanSizeLookup(androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup!);
+    method public void setUsingSpansToEstimateScrollbarDimensions(boolean);
+    field public static final int DEFAULT_SPAN_COUNT = -1; // 0xffffffff
+  }
+
+  public static final class GridLayoutManager.DefaultSpanSizeLookup extends androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.DefaultSpanSizeLookup();
+    method public int getSpanSize(int);
+  }
+
+  public static class GridLayoutManager.LayoutParams extends androidx.recyclerview.widget.RecyclerView.LayoutParams {
+    ctor public GridLayoutManager.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public GridLayoutManager.LayoutParams(int, int);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams!);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams!);
+    ctor public GridLayoutManager.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public int getSpanIndex();
+    method public int getSpanSize();
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+  public abstract static class GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.SpanSizeLookup();
+    method public int getSpanGroupIndex(int, int);
+    method public int getSpanIndex(int, int);
+    method public abstract int getSpanSize(int);
+    method public void invalidateSpanGroupIndexCache();
+    method public void invalidateSpanIndexCache();
+    method public boolean isSpanGroupIndexCacheEnabled();
+    method public boolean isSpanIndexCacheEnabled();
+    method public void setSpanGroupIndexCacheEnabled(boolean);
+    method public void setSpanIndexCacheEnabled(boolean);
+  }
+
+  public class ItemTouchHelper extends androidx.recyclerview.widget.RecyclerView.ItemDecoration implements androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener {
+    ctor public ItemTouchHelper(androidx.recyclerview.widget.ItemTouchHelper.Callback);
+    method public void attachToRecyclerView(androidx.recyclerview.widget.RecyclerView?);
+    method public void onChildViewAttachedToWindow(android.view.View);
+    method public void onChildViewDetachedFromWindow(android.view.View);
+    method public void startDrag(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void startSwipe(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    field public static final int ACTION_STATE_DRAG = 2; // 0x2
+    field public static final int ACTION_STATE_IDLE = 0; // 0x0
+    field public static final int ACTION_STATE_SWIPE = 1; // 0x1
+    field public static final int ANIMATION_TYPE_DRAG = 8; // 0x8
+    field public static final int ANIMATION_TYPE_SWIPE_CANCEL = 4; // 0x4
+    field public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 2; // 0x2
+    field public static final int DOWN = 2; // 0x2
+    field public static final int END = 32; // 0x20
+    field public static final int LEFT = 4; // 0x4
+    field public static final int RIGHT = 8; // 0x8
+    field public static final int START = 16; // 0x10
+    field public static final int UP = 1; // 0x1
+  }
+
+  public abstract static class ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.Callback();
+    method public boolean canDropOver(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? chooseDropTarget(androidx.recyclerview.widget.RecyclerView.ViewHolder, java.util.List<androidx.recyclerview.widget.RecyclerView.ViewHolder!>, int, int);
+    method public void clearView(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public int convertToAbsoluteDirection(int, int);
+    method public static int convertToRelativeDirection(int, int);
+    method public long getAnimationDuration(androidx.recyclerview.widget.RecyclerView, int, float, float);
+    method public int getBoundingBoxMargin();
+    method public static androidx.recyclerview.widget.ItemTouchUIUtil getDefaultUIUtil();
+    method public float getMoveThreshold(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public abstract int getMovementFlags(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public float getSwipeEscapeVelocity(float);
+    method public float getSwipeThreshold(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public float getSwipeVelocityThreshold(float);
+    method public int interpolateOutOfBoundsScroll(androidx.recyclerview.widget.RecyclerView, int, int, int, long);
+    method public boolean isItemViewSwipeEnabled();
+    method public boolean isLongPressDragEnabled();
+    method public static int makeFlag(int, int);
+    method public static int makeMovementFlags(int, int);
+    method public void onChildDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public void onChildDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public abstract boolean onMove(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onMoved(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int);
+    method public void onSelectedChanged(androidx.recyclerview.widget.RecyclerView.ViewHolder?, int);
+    method public abstract void onSwiped(androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
+    field public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200; // 0xc8
+    field public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250; // 0xfa
+  }
+
+  public abstract static class ItemTouchHelper.SimpleCallback extends androidx.recyclerview.widget.ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.SimpleCallback(int, int);
+    method public int getDragDirs(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public int getMovementFlags(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public int getSwipeDirs(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void setDefaultDragDirs(int);
+    method public void setDefaultSwipeDirs(int);
+  }
+
+  public static interface ItemTouchHelper.ViewDropHandler {
+    method public void prepareForDrop(android.view.View, android.view.View, int, int);
+  }
+
+  public interface ItemTouchUIUtil {
+    method public void clearView(android.view.View);
+    method public void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public void onSelected(android.view.View);
+  }
+
+  public class LinearLayoutManager extends androidx.recyclerview.widget.RecyclerView.LayoutManager implements androidx.recyclerview.widget.ItemTouchHelper.ViewDropHandler androidx.recyclerview.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
+    ctor public LinearLayoutManager(android.content.Context);
+    ctor public LinearLayoutManager(android.content.Context, int, boolean);
+    ctor public LinearLayoutManager(android.content.Context, android.util.AttributeSet?, int, int);
+    method protected void calculateExtraLayoutSpace(androidx.recyclerview.widget.RecyclerView.State, int[]);
+    method public android.graphics.PointF? computeScrollVectorForPosition(int);
+    method public int findFirstCompletelyVisibleItemPosition();
+    method public int findFirstVisibleItemPosition();
+    method public int findLastCompletelyVisibleItemPosition();
+    method public int findLastVisibleItemPosition();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method @Deprecated protected int getExtraLayoutSpace(androidx.recyclerview.widget.RecyclerView.State!);
+    method public int getInitialPrefetchItemCount();
+    method public int getOrientation();
+    method public boolean getRecycleChildrenOnDetach();
+    method public boolean getReverseLayout();
+    method public boolean getStackFromEnd();
+    method protected boolean isLayoutRTL();
+    method public boolean isSmoothScrollbarEnabled();
+    method public void prepareForDrop(android.view.View, android.view.View, int, int);
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setInitialPrefetchItemCount(int);
+    method public void setOrientation(int);
+    method public void setRecycleChildrenOnDetach(boolean);
+    method public void setReverseLayout(boolean);
+    method public void setSmoothScrollbarEnabled(boolean);
+    method public void setStackFromEnd(boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_OFFSET = -2147483648; // 0x80000000
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  protected static class LinearLayoutManager.LayoutChunkResult {
+    ctor protected LinearLayoutManager.LayoutChunkResult();
+    field public int mConsumed;
+    field public boolean mFinished;
+    field public boolean mFocusable;
+    field public boolean mIgnoreConsumed;
+  }
+
+  public class LinearSmoothScroller extends androidx.recyclerview.widget.RecyclerView.SmoothScroller {
+    ctor public LinearSmoothScroller(android.content.Context);
+    method public int calculateDtToFit(int, int, int, int, int);
+    method public int calculateDxToMakeVisible(android.view.View, int);
+    method public int calculateDyToMakeVisible(android.view.View, int);
+    method protected float calculateSpeedPerPixel(android.util.DisplayMetrics);
+    method protected int calculateTimeForDeceleration(int);
+    method protected int calculateTimeForScrolling(int);
+    method protected int getHorizontalSnapPreference();
+    method protected int getVerticalSnapPreference();
+    method protected void onSeekTargetStep(int, int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method protected void onStart();
+    method protected void onStop();
+    method protected void onTargetFound(android.view.View, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method protected void updateActionForInterimTarget(androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    field public static final int SNAP_TO_ANY = 0; // 0x0
+    field public static final int SNAP_TO_END = 1; // 0x1
+    field public static final int SNAP_TO_START = -1; // 0xffffffff
+    field protected final android.view.animation.DecelerateInterpolator! mDecelerateInterpolator;
+    field protected int mInterimTargetDx;
+    field protected int mInterimTargetDy;
+    field protected final android.view.animation.LinearInterpolator! mLinearInterpolator;
+    field protected android.graphics.PointF? mTargetVector;
+  }
+
+  public class LinearSnapHelper extends androidx.recyclerview.widget.SnapHelper {
+    ctor public LinearSnapHelper();
+    method public int[]! calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
+    method public android.view.View! findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager!);
+    method public int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager!, int, int);
+  }
+
+  public abstract class ListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
+    ctor protected ListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T!>);
+    ctor protected ListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T!>);
+    method public java.util.List<T!> getCurrentList();
+    method protected T! getItem(int);
+    method public int getItemCount();
+    method public void onCurrentListChanged(java.util.List<T!>, java.util.List<T!>);
+    method public void submitList(java.util.List<T!>?);
+    method public void submitList(java.util.List<T!>?, Runnable?);
+  }
+
+  public interface ListUpdateCallback {
+    method public void onChanged(int, int, Object?);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public abstract class OrientationHelper {
+    method public static androidx.recyclerview.widget.OrientationHelper! createHorizontalHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager!);
+    method public static androidx.recyclerview.widget.OrientationHelper! createOrientationHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager!, int);
+    method public static androidx.recyclerview.widget.OrientationHelper! createVerticalHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager!);
+    method public abstract int getDecoratedEnd(android.view.View!);
+    method public abstract int getDecoratedMeasurement(android.view.View!);
+    method public abstract int getDecoratedMeasurementInOther(android.view.View!);
+    method public abstract int getDecoratedStart(android.view.View!);
+    method public abstract int getEnd();
+    method public abstract int getEndAfterPadding();
+    method public abstract int getEndPadding();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutManager! getLayoutManager();
+    method public abstract int getMode();
+    method public abstract int getModeInOther();
+    method public abstract int getStartAfterPadding();
+    method public abstract int getTotalSpace();
+    method public int getTotalSpaceChange();
+    method public abstract int getTransformedEndWithDecoration(android.view.View!);
+    method public abstract int getTransformedStartWithDecoration(android.view.View!);
+    method public abstract void offsetChild(android.view.View!, int);
+    method public abstract void offsetChildren(int);
+    method public void onLayoutComplete();
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+    field protected final androidx.recyclerview.widget.RecyclerView.LayoutManager! mLayoutManager;
+  }
+
+  public class PagerSnapHelper extends androidx.recyclerview.widget.SnapHelper {
+    ctor public PagerSnapHelper();
+    method public int[]? calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
+    method public android.view.View? findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method public int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager, int, int);
+  }
+
+  public class RecyclerView extends android.view.ViewGroup implements androidx.core.view.NestedScrollingChild2 androidx.core.view.NestedScrollingChild3 androidx.core.view.ScrollingView {
+    ctor public RecyclerView(android.content.Context);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet?);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet?, int);
+    method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration, int);
+    method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
+    method public void addOnChildAttachStateChangeListener(androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void addOnItemTouchListener(androidx.recyclerview.widget.RecyclerView.OnItemTouchListener);
+    method public void addOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener);
+    method public void addRecyclerListener(androidx.recyclerview.widget.RecyclerView.RecyclerListener);
+    method public void clearOnChildAttachStateChangeListeners();
+    method public void clearOnScrollListeners();
+    method public int computeHorizontalScrollExtent();
+    method public int computeHorizontalScrollOffset();
+    method public int computeHorizontalScrollRange();
+    method public int computeVerticalScrollExtent();
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
+    method public boolean dispatchNestedPreScroll(int, int, int[]!, int[]!, int);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]!, int);
+    method public final void dispatchNestedScroll(int, int, int, int, int[]!, int, int[]);
+    method public boolean drawChild(android.graphics.Canvas!, android.view.View!, long);
+    method public android.view.View? findChildViewUnder(float, float);
+    method public android.view.View? findContainingItemView(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? findContainingViewHolder(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? findViewHolderForAdapterPosition(int);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder! findViewHolderForItemId(long);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? findViewHolderForLayoutPosition(int);
+    method @Deprecated public androidx.recyclerview.widget.RecyclerView.ViewHolder? findViewHolderForPosition(int);
+    method public boolean fling(int, int);
+    method public androidx.recyclerview.widget.RecyclerView.Adapter? getAdapter();
+    method public int getChildAdapterPosition(android.view.View);
+    method public long getChildItemId(android.view.View);
+    method public int getChildLayoutPosition(android.view.View);
+    method @Deprecated public int getChildPosition(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder! getChildViewHolder(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate? getCompatAccessibilityDelegate();
+    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
+    method public androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory getEdgeEffectFactory();
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator? getItemAnimator();
+    method public androidx.recyclerview.widget.RecyclerView.ItemDecoration getItemDecorationAt(int);
+    method public int getItemDecorationCount();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutManager? getLayoutManager();
+    method public int getMaxFlingVelocity();
+    method public int getMinFlingVelocity();
+    method public androidx.recyclerview.widget.RecyclerView.OnFlingListener? getOnFlingListener();
+    method public boolean getPreserveFocusAfterLayout();
+    method public androidx.recyclerview.widget.RecyclerView.RecycledViewPool getRecycledViewPool();
+    method public int getScrollState();
+    method public boolean hasFixedSize();
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean hasPendingAdapterUpdates();
+    method public void invalidateItemDecorations();
+    method public boolean isAnimating();
+    method public boolean isComputingLayout();
+    method @Deprecated public boolean isLayoutFrozen();
+    method public final boolean isLayoutSuppressed();
+    method public void nestedScrollBy(int, int);
+    method public void offsetChildrenHorizontal(@Px int);
+    method public void offsetChildrenVertical(@Px int);
+    method public void onChildAttachedToWindow(android.view.View);
+    method public void onChildDetachedFromWindow(android.view.View);
+    method public void onDraw(android.graphics.Canvas!);
+    method public void onScrollStateChanged(int);
+    method public void onScrolled(@Px int, @Px int);
+    method public void removeItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
+    method public void removeItemDecorationAt(int);
+    method public void removeOnChildAttachStateChangeListener(androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void removeOnItemTouchListener(androidx.recyclerview.widget.RecyclerView.OnItemTouchListener);
+    method public void removeOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener);
+    method public void removeRecyclerListener(androidx.recyclerview.widget.RecyclerView.RecyclerListener);
+    method public void scrollToPosition(int);
+    method public void setAccessibilityDelegateCompat(androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate?);
+    method public void setAdapter(androidx.recyclerview.widget.RecyclerView.Adapter?);
+    method public void setChildDrawingOrderCallback(androidx.recyclerview.widget.RecyclerView.ChildDrawingOrderCallback?);
+    method public void setEdgeEffectFactory(androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory);
+    method public void setHasFixedSize(boolean);
+    method public void setItemAnimator(androidx.recyclerview.widget.RecyclerView.ItemAnimator?);
+    method public void setItemViewCacheSize(int);
+    method @Deprecated public void setLayoutFrozen(boolean);
+    method public void setLayoutManager(androidx.recyclerview.widget.RecyclerView.LayoutManager?);
+    method @Deprecated public void setLayoutTransition(android.animation.LayoutTransition!);
+    method public void setOnFlingListener(androidx.recyclerview.widget.RecyclerView.OnFlingListener?);
+    method @Deprecated public void setOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener?);
+    method public void setPreserveFocusAfterLayout(boolean);
+    method public void setRecycledViewPool(androidx.recyclerview.widget.RecyclerView.RecycledViewPool?);
+    method @Deprecated public void setRecyclerListener(androidx.recyclerview.widget.RecyclerView.RecyclerListener?);
+    method public void setScrollingTouchSlop(int);
+    method public void setViewCacheExtension(androidx.recyclerview.widget.RecyclerView.ViewCacheExtension?);
+    method public void smoothScrollBy(@Px int, @Px int);
+    method public void smoothScrollBy(@Px int, @Px int, android.view.animation.Interpolator?);
+    method public void smoothScrollBy(@Px int, @Px int, android.view.animation.Interpolator?, int);
+    method public void smoothScrollToPosition(int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll(int);
+    method public void stopScroll();
+    method public final void suppressLayout(boolean);
+    method public void swapAdapter(androidx.recyclerview.widget.RecyclerView.Adapter?, boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_TYPE = -1; // 0xffffffff
+    field public static final long NO_ID = -1L; // 0xffffffffffffffffL
+    field public static final int NO_POSITION = -1; // 0xffffffff
+    field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
+    field public static final int SCROLL_STATE_IDLE = 0; // 0x0
+    field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
+    field public static final int TOUCH_SLOP_DEFAULT = 0; // 0x0
+    field public static final int TOUCH_SLOP_PAGING = 1; // 0x1
+    field public static final int UNDEFINED_DURATION = -2147483648; // 0x80000000
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public abstract static class RecyclerView.Adapter<VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> {
+    ctor public RecyclerView.Adapter();
+    method public final void bindViewHolder(VH, int);
+    method public final VH createViewHolder(android.view.ViewGroup, int);
+    method public int findRelativeAdapterPositionIn(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>, androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
+    method public abstract int getItemCount();
+    method public long getItemId(int);
+    method public int getItemViewType(int);
+    method public final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy getStateRestorationPolicy();
+    method public final boolean hasObservers();
+    method public final boolean hasStableIds();
+    method public final void notifyDataSetChanged();
+    method public final void notifyItemChanged(int);
+    method public final void notifyItemChanged(int, Object?);
+    method public final void notifyItemInserted(int);
+    method public final void notifyItemMoved(int, int);
+    method public final void notifyItemRangeChanged(int, int);
+    method public final void notifyItemRangeChanged(int, int, Object?);
+    method public final void notifyItemRangeInserted(int, int);
+    method public final void notifyItemRangeRemoved(int, int);
+    method public final void notifyItemRemoved(int);
+    method public void onAttachedToRecyclerView(androidx.recyclerview.widget.RecyclerView);
+    method public abstract void onBindViewHolder(VH, int);
+    method public void onBindViewHolder(VH, int, java.util.List<java.lang.Object!>);
+    method public abstract VH onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onDetachedFromRecyclerView(androidx.recyclerview.widget.RecyclerView);
+    method public boolean onFailedToRecycleView(VH);
+    method public void onViewAttachedToWindow(VH);
+    method public void onViewDetachedFromWindow(VH);
+    method public void onViewRecycled(VH);
+    method public void registerAdapterDataObserver(androidx.recyclerview.widget.RecyclerView.AdapterDataObserver);
+    method public void setHasStableIds(boolean);
+    method public void setStateRestorationPolicy(androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy);
+    method public void unregisterAdapterDataObserver(androidx.recyclerview.widget.RecyclerView.AdapterDataObserver);
+  }
+
+  public enum RecyclerView.Adapter.StateRestorationPolicy {
+    enum_constant public static final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy ALLOW;
+    enum_constant public static final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy PREVENT;
+    enum_constant public static final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy PREVENT_WHEN_EMPTY;
+  }
+
+  public abstract static class RecyclerView.AdapterDataObserver {
+    ctor public RecyclerView.AdapterDataObserver();
+    method public void onChanged();
+    method public void onItemRangeChanged(int, int);
+    method public void onItemRangeChanged(int, int, Object?);
+    method public void onItemRangeInserted(int, int);
+    method public void onItemRangeMoved(int, int, int);
+    method public void onItemRangeRemoved(int, int);
+    method public void onStateRestorationPolicyChanged();
+  }
+
+  public static interface RecyclerView.ChildDrawingOrderCallback {
+    method public int onGetChildDrawingOrder(int, int);
+  }
+
+  public static class RecyclerView.EdgeEffectFactory {
+    ctor public RecyclerView.EdgeEffectFactory();
+    method protected android.widget.EdgeEffect createEdgeEffect(androidx.recyclerview.widget.RecyclerView, @androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.EdgeDirection int);
+    field public static final int DIRECTION_BOTTOM = 3; // 0x3
+    field public static final int DIRECTION_LEFT = 0; // 0x0
+    field public static final int DIRECTION_RIGHT = 2; // 0x2
+    field public static final int DIRECTION_TOP = 1; // 0x1
+  }
+
+  @IntDef({androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_LEFT, androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_TOP, androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_RIGHT, androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_BOTTOM}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RecyclerView.EdgeEffectFactory.EdgeDirection {
+  }
+
+  public abstract static class RecyclerView.ItemAnimator {
+    ctor public RecyclerView.ItemAnimator();
+    method public abstract boolean animateAppearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateDisappearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?);
+    method public abstract boolean animatePersistence(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean canReuseUpdatedViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean canReuseUpdatedViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder, java.util.List<java.lang.Object!>);
+    method public final void dispatchAnimationFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationStarted(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationsFinished();
+    method public abstract void endAnimation(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public abstract void endAnimations();
+    method public long getAddDuration();
+    method public long getChangeDuration();
+    method public long getMoveDuration();
+    method public long getRemoveDuration();
+    method public abstract boolean isRunning();
+    method public final boolean isRunning(androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemAnimatorFinishedListener?);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo obtainHolderInfo();
+    method public void onAnimationFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onAnimationStarted(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPostLayoutInformation(androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPreLayoutInformation(androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.ViewHolder, @androidx.recyclerview.widget.RecyclerView.ItemAnimator.AdapterChanges int, java.util.List<java.lang.Object!>);
+    method public abstract void runPendingAnimations();
+    method public void setAddDuration(long);
+    method public void setChangeDuration(long);
+    method public void setMoveDuration(long);
+    method public void setRemoveDuration(long);
+    field public static final int FLAG_APPEARED_IN_PRE_LAYOUT = 4096; // 0x1000
+    field public static final int FLAG_CHANGED = 2; // 0x2
+    field public static final int FLAG_INVALIDATED = 4; // 0x4
+    field public static final int FLAG_MOVED = 2048; // 0x800
+    field public static final int FLAG_REMOVED = 8; // 0x8
+  }
+
+  @IntDef(flag=true, value={androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_CHANGED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_REMOVED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_MOVED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_INVALIDATED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RecyclerView.ItemAnimator.AdapterChanges {
+  }
+
+  public static interface RecyclerView.ItemAnimator.ItemAnimatorFinishedListener {
+    method public void onAnimationsFinished();
+  }
+
+  public static class RecyclerView.ItemAnimator.ItemHolderInfo {
+    ctor public RecyclerView.ItemAnimator.ItemHolderInfo();
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(androidx.recyclerview.widget.RecyclerView.ViewHolder, @androidx.recyclerview.widget.RecyclerView.ItemAnimator.AdapterChanges int);
+    field public int bottom;
+    field @androidx.recyclerview.widget.RecyclerView.ItemAnimator.AdapterChanges public int changeFlags;
+    field public int left;
+    field public int right;
+    field public int top;
+  }
+
+  public abstract static class RecyclerView.ItemDecoration {
+    ctor public RecyclerView.ItemDecoration();
+    method @Deprecated public void getItemOffsets(android.graphics.Rect, int, androidx.recyclerview.widget.RecyclerView);
+    method public void getItemOffsets(android.graphics.Rect, android.view.View, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
+    method public void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
+    method @Deprecated public void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView);
+    method public void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
+    method @Deprecated public void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView);
+  }
+
+  public abstract static class RecyclerView.LayoutManager {
+    ctor public RecyclerView.LayoutManager();
+    method public void addDisappearingView(android.view.View!);
+    method public void addDisappearingView(android.view.View!, int);
+    method public void addView(android.view.View!);
+    method public void addView(android.view.View!, int);
+    method public void assertInLayoutOrScroll(String!);
+    method public void assertNotInLayoutOrScroll(String?);
+    method public void attachView(android.view.View, int, androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public void attachView(android.view.View, int);
+    method public void attachView(android.view.View);
+    method public void calculateItemDecorationsForChild(android.view.View, android.graphics.Rect);
+    method public boolean canScrollHorizontally();
+    method public boolean canScrollVertically();
+    method public boolean checkLayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public static int chooseSize(int, int, int);
+    method public void collectAdjacentPrefetchPositions(int, int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
+    method public void collectInitialPrefetchPositions(int, androidx.recyclerview.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
+    method public int computeHorizontalScrollExtent(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeHorizontalScrollOffset(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeHorizontalScrollRange(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeVerticalScrollExtent(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeVerticalScrollOffset(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeVerticalScrollRange(androidx.recyclerview.widget.RecyclerView.State);
+    method public void detachAndScrapAttachedViews(androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void detachAndScrapView(android.view.View, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void detachAndScrapViewAt(int, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void detachView(android.view.View);
+    method public void detachViewAt(int);
+    method public void endAnimation(android.view.View!);
+    method public android.view.View? findContainingItemView(android.view.View);
+    method public android.view.View? findViewByPosition(int);
+    method public abstract androidx.recyclerview.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams! generateLayoutParams(android.view.ViewGroup.LayoutParams!);
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams! generateLayoutParams(android.content.Context!, android.util.AttributeSet!);
+    method public int getBaseline();
+    method public int getBottomDecorationHeight(android.view.View);
+    method public android.view.View? getChildAt(int);
+    method public int getChildCount();
+    method @Deprecated public static int getChildMeasureSpec(int, int, int, boolean);
+    method public static int getChildMeasureSpec(int, int, int, int, boolean);
+    method public boolean getClipToPadding();
+    method public int getColumnCountForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public int getDecoratedBottom(android.view.View);
+    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
+    method public int getDecoratedLeft(android.view.View);
+    method public int getDecoratedMeasuredHeight(android.view.View);
+    method public int getDecoratedMeasuredWidth(android.view.View);
+    method public int getDecoratedRight(android.view.View);
+    method public int getDecoratedTop(android.view.View);
+    method public android.view.View? getFocusedChild();
+    method @Px public int getHeight();
+    method public int getHeightMode();
+    method public int getItemCount();
+    method public int getItemViewType(android.view.View);
+    method public int getLayoutDirection();
+    method public int getLeftDecorationWidth(android.view.View);
+    method @Px public int getMinimumHeight();
+    method @Px public int getMinimumWidth();
+    method @Px public int getPaddingBottom();
+    method @Px public int getPaddingEnd();
+    method @Px public int getPaddingLeft();
+    method @Px public int getPaddingRight();
+    method @Px public int getPaddingStart();
+    method @Px public int getPaddingTop();
+    method public int getPosition(android.view.View);
+    method public static androidx.recyclerview.widget.RecyclerView.LayoutManager.Properties! getProperties(android.content.Context, android.util.AttributeSet?, int, int);
+    method public int getRightDecorationWidth(android.view.View);
+    method public int getRowCountForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public int getSelectionModeForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public int getTopDecorationHeight(android.view.View);
+    method public void getTransformedBoundingBox(android.view.View, boolean, android.graphics.Rect);
+    method @Px public int getWidth();
+    method public int getWidthMode();
+    method public boolean hasFocus();
+    method public void ignoreView(android.view.View);
+    method public boolean isAttachedToWindow();
+    method public boolean isAutoMeasureEnabled();
+    method public boolean isFocused();
+    method public final boolean isItemPrefetchEnabled();
+    method public boolean isLayoutHierarchical(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public boolean isMeasurementCacheEnabled();
+    method public boolean isSmoothScrolling();
+    method public boolean isViewPartiallyVisible(android.view.View, boolean, boolean);
+    method public void layoutDecorated(android.view.View, int, int, int, int);
+    method public void layoutDecoratedWithMargins(android.view.View, int, int, int, int);
+    method public void measureChild(android.view.View, int, int);
+    method public void measureChildWithMargins(android.view.View, int, int);
+    method public void moveView(int, int);
+    method public void offsetChildrenHorizontal(@Px int);
+    method public void offsetChildrenVertical(@Px int);
+    method public void onAdapterChanged(androidx.recyclerview.widget.RecyclerView.Adapter?, androidx.recyclerview.widget.RecyclerView.Adapter?);
+    method public boolean onAddFocusables(androidx.recyclerview.widget.RecyclerView, java.util.ArrayList<android.view.View!>, int, int);
+    method @CallSuper public void onAttachedToWindow(androidx.recyclerview.widget.RecyclerView!);
+    method @Deprecated public void onDetachedFromWindow(androidx.recyclerview.widget.RecyclerView!);
+    method @CallSuper public void onDetachedFromWindow(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public android.view.View? onFocusSearchFailed(android.view.View, int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityEvent(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+    method public void onInitializeAccessibilityNodeInfoForItem(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+    method public android.view.View? onInterceptFocusSearch(android.view.View, int);
+    method public void onItemsAdded(androidx.recyclerview.widget.RecyclerView, int, int);
+    method public void onItemsChanged(androidx.recyclerview.widget.RecyclerView);
+    method public void onItemsMoved(androidx.recyclerview.widget.RecyclerView, int, int, int);
+    method public void onItemsRemoved(androidx.recyclerview.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(androidx.recyclerview.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(androidx.recyclerview.widget.RecyclerView, int, int, Object?);
+    method public void onLayoutChildren(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public void onLayoutCompleted(androidx.recyclerview.widget.RecyclerView.State);
+    method public void onMeasure(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, int, int);
+    method @Deprecated public boolean onRequestChildFocus(androidx.recyclerview.widget.RecyclerView, android.view.View, android.view.View?);
+    method public boolean onRequestChildFocus(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State, android.view.View, android.view.View?);
+    method public void onRestoreInstanceState(android.os.Parcelable);
+    method public android.os.Parcelable? onSaveInstanceState();
+    method public void onScrollStateChanged(int);
+    method public boolean performAccessibilityAction(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, int, android.os.Bundle?);
+    method public boolean performAccessibilityActionForItem(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.View, int, android.os.Bundle?);
+    method public void postOnAnimation(Runnable!);
+    method public void removeAllViews();
+    method public void removeAndRecycleAllViews(androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleView(android.view.View, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleViewAt(int, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public boolean removeCallbacks(Runnable!);
+    method public void removeDetachedView(android.view.View);
+    method public void removeView(android.view.View!);
+    method public void removeViewAt(int);
+    method public boolean requestChildRectangleOnScreen(androidx.recyclerview.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean);
+    method public boolean requestChildRectangleOnScreen(androidx.recyclerview.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean, boolean);
+    method public void requestLayout();
+    method public void requestSimpleAnimationsInNextLayout();
+    method public int scrollHorizontallyBy(int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public void scrollToPosition(int);
+    method public int scrollVerticallyBy(int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method @Deprecated public void setAutoMeasureEnabled(boolean);
+    method public final void setItemPrefetchEnabled(boolean);
+    method public void setMeasuredDimension(android.graphics.Rect!, int, int);
+    method public void setMeasuredDimension(int, int);
+    method public void setMeasurementCacheEnabled(boolean);
+    method public void smoothScrollToPosition(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State, int);
+    method public void startSmoothScroll(androidx.recyclerview.widget.RecyclerView.SmoothScroller!);
+    method public void stopIgnoringView(android.view.View);
+    method public boolean supportsPredictiveItemAnimations();
+  }
+
+  public static interface RecyclerView.LayoutManager.LayoutPrefetchRegistry {
+    method public void addPosition(int, int);
+  }
+
+  public static class RecyclerView.LayoutManager.Properties {
+    ctor public RecyclerView.LayoutManager.Properties();
+    field public int orientation;
+    field public boolean reverseLayout;
+    field public int spanCount;
+    field public boolean stackFromEnd;
+  }
+
+  public static class RecyclerView.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public RecyclerView.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public RecyclerView.LayoutParams(int, int);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.MarginLayoutParams!);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.LayoutParams!);
+    ctor public RecyclerView.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public int getAbsoluteAdapterPosition();
+    method public int getBindingAdapterPosition();
+    method @Deprecated public int getViewAdapterPosition();
+    method public int getViewLayoutPosition();
+    method @Deprecated public int getViewPosition();
+    method public boolean isItemChanged();
+    method public boolean isItemRemoved();
+    method public boolean isViewInvalid();
+    method public boolean viewNeedsUpdate();
+  }
+
+  public static interface RecyclerView.OnChildAttachStateChangeListener {
+    method public void onChildViewAttachedToWindow(android.view.View);
+    method public void onChildViewDetachedFromWindow(android.view.View);
+  }
+
+  public abstract static class RecyclerView.OnFlingListener {
+    ctor public RecyclerView.OnFlingListener();
+    method public abstract boolean onFling(int, int);
+  }
+
+  public static interface RecyclerView.OnItemTouchListener {
+    method public boolean onInterceptTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+    method public void onRequestDisallowInterceptTouchEvent(boolean);
+    method public void onTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public abstract static class RecyclerView.OnScrollListener {
+    ctor public RecyclerView.OnScrollListener();
+    method public void onScrollStateChanged(androidx.recyclerview.widget.RecyclerView, int);
+    method public void onScrolled(androidx.recyclerview.widget.RecyclerView, int, int);
+  }
+
+  public static class RecyclerView.RecycledViewPool {
+    ctor public RecyclerView.RecycledViewPool();
+    method public void clear();
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? getRecycledView(int);
+    method public int getRecycledViewCount(int);
+    method public void putRecycledView(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void setMaxRecycledViews(int, int);
+  }
+
+  public final class RecyclerView.Recycler {
+    ctor public RecyclerView.Recycler();
+    method public void bindViewToPosition(android.view.View, int);
+    method public void clear();
+    method public int convertPreLayoutPositionToPostLayout(int);
+    method public java.util.List<androidx.recyclerview.widget.RecyclerView.ViewHolder!> getScrapList();
+    method public android.view.View getViewForPosition(int);
+    method public void recycleView(android.view.View);
+    method public void setViewCacheSize(int);
+  }
+
+  public static interface RecyclerView.RecyclerListener {
+    method public void onViewRecycled(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+  }
+
+  public static class RecyclerView.SimpleOnItemTouchListener implements androidx.recyclerview.widget.RecyclerView.OnItemTouchListener {
+    ctor public RecyclerView.SimpleOnItemTouchListener();
+    method public boolean onInterceptTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+    method public void onRequestDisallowInterceptTouchEvent(boolean);
+    method public void onTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public abstract static class RecyclerView.SmoothScroller {
+    ctor public RecyclerView.SmoothScroller();
+    method public android.graphics.PointF? computeScrollVectorForPosition(int);
+    method public android.view.View! findViewByPosition(int);
+    method public int getChildCount();
+    method public int getChildPosition(android.view.View!);
+    method public androidx.recyclerview.widget.RecyclerView.LayoutManager? getLayoutManager();
+    method public int getTargetPosition();
+    method @Deprecated public void instantScrollToPosition(int);
+    method public boolean isPendingInitialRun();
+    method public boolean isRunning();
+    method protected void normalize(android.graphics.PointF);
+    method protected void onChildAttachedToWindow(android.view.View!);
+    method protected abstract void onSeekTargetStep(@Px int, @Px int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method protected abstract void onStart();
+    method protected abstract void onStop();
+    method protected abstract void onTargetFound(android.view.View, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method public void setTargetPosition(int);
+    method protected final void stop();
+  }
+
+  public static class RecyclerView.SmoothScroller.Action {
+    ctor public RecyclerView.SmoothScroller.Action(@Px int, @Px int);
+    ctor public RecyclerView.SmoothScroller.Action(@Px int, @Px int, int);
+    ctor public RecyclerView.SmoothScroller.Action(@Px int, @Px int, int, android.view.animation.Interpolator?);
+    method public int getDuration();
+    method @Px public int getDx();
+    method @Px public int getDy();
+    method public android.view.animation.Interpolator? getInterpolator();
+    method public void jumpTo(int);
+    method public void setDuration(int);
+    method public void setDx(@Px int);
+    method public void setDy(@Px int);
+    method public void setInterpolator(android.view.animation.Interpolator?);
+    method public void update(@Px int, @Px int, int, android.view.animation.Interpolator?);
+    field public static final int UNDEFINED_DURATION = -2147483648; // 0x80000000
+  }
+
+  public static interface RecyclerView.SmoothScroller.ScrollVectorProvider {
+    method public android.graphics.PointF? computeScrollVectorForPosition(int);
+  }
+
+  public static class RecyclerView.State {
+    ctor public RecyclerView.State();
+    method public boolean didStructureChange();
+    method public <T> T! get(int);
+    method public int getItemCount();
+    method public int getRemainingScrollHorizontal();
+    method public int getRemainingScrollVertical();
+    method public int getTargetScrollPosition();
+    method public boolean hasTargetScrollPosition();
+    method public boolean isMeasuring();
+    method public boolean isPreLayout();
+    method public void put(int, Object!);
+    method public void remove(int);
+    method public boolean willRunPredictiveAnimations();
+    method public boolean willRunSimpleAnimations();
+  }
+
+  public abstract static class RecyclerView.ViewCacheExtension {
+    ctor public RecyclerView.ViewCacheExtension();
+    method public abstract android.view.View? getViewForPositionAndType(androidx.recyclerview.widget.RecyclerView.Recycler, int, int);
+  }
+
+  public abstract static class RecyclerView.ViewHolder {
+    ctor public RecyclerView.ViewHolder(android.view.View);
+    method public final int getAbsoluteAdapterPosition();
+    method @Deprecated public final int getAdapterPosition();
+    method public final androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>? getBindingAdapter();
+    method public final int getBindingAdapterPosition();
+    method public final long getItemId();
+    method public final int getItemViewType();
+    method public final int getLayoutPosition();
+    method public final int getOldPosition();
+    method @Deprecated public final int getPosition();
+    method public final boolean isRecyclable();
+    method public final void setIsRecyclable(boolean);
+    field public final android.view.View itemView;
+  }
+
+  public class RecyclerViewAccessibilityDelegate extends androidx.core.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate(androidx.recyclerview.widget.RecyclerView);
+    method public androidx.core.view.AccessibilityDelegateCompat getItemDelegate();
+  }
+
+  public static class RecyclerViewAccessibilityDelegate.ItemDelegate extends androidx.core.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate.ItemDelegate(androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate);
+  }
+
+  public abstract class SimpleItemAnimator extends androidx.recyclerview.widget.RecyclerView.ItemAnimator {
+    ctor public SimpleItemAnimator();
+    method public abstract boolean animateAdd(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean animateAppearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder?, int, int, int, int);
+    method public boolean animateDisappearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?);
+    method public abstract boolean animateMove(androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animatePersistence(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateRemove(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAddFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchAddStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchChangeFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public final void dispatchChangeStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public final void dispatchMoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchMoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchRemoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchRemoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public boolean getSupportsChangeAnimations();
+    method public void onAddFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onAddStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onChangeFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public void onChangeStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public void onMoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onMoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onRemoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onRemoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void setSupportsChangeAnimations(boolean);
+  }
+
+  public abstract class SnapHelper extends androidx.recyclerview.widget.RecyclerView.OnFlingListener {
+    ctor public SnapHelper();
+    method public void attachToRecyclerView(androidx.recyclerview.widget.RecyclerView?) throws java.lang.IllegalStateException;
+    method public abstract int[]? calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
+    method public int[] calculateScrollDistance(int, int);
+    method protected androidx.recyclerview.widget.RecyclerView.SmoothScroller? createScroller(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method @Deprecated protected androidx.recyclerview.widget.LinearSmoothScroller? createSnapScroller(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method public abstract android.view.View? findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method public abstract int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager, int, int);
+    method public boolean onFling(int, int);
+  }
+
+  public class SortedList<T> {
+    ctor public SortedList(Class<T!>, androidx.recyclerview.widget.SortedList.Callback<T!>);
+    ctor public SortedList(Class<T!>, androidx.recyclerview.widget.SortedList.Callback<T!>, int);
+    method public int add(T!);
+    method public void addAll(T![], boolean);
+    method public void addAll(T!...);
+    method public void addAll(java.util.Collection<T!>);
+    method public void beginBatchedUpdates();
+    method public void clear();
+    method public void endBatchedUpdates();
+    method public T! get(int) throws java.lang.IndexOutOfBoundsException;
+    method public int indexOf(T!);
+    method public void recalculatePositionOfItemAt(int);
+    method public boolean remove(T!);
+    method public T! removeItemAt(int);
+    method public void replaceAll(T![], boolean);
+    method public void replaceAll(T!...);
+    method public void replaceAll(java.util.Collection<T!>);
+    method public int size();
+    method public void updateItemAt(int, T!);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static class SortedList.BatchedCallback<T2> extends androidx.recyclerview.widget.SortedList.Callback<T2> {
+    ctor public SortedList.BatchedCallback(androidx.recyclerview.widget.SortedList.Callback<T2!>);
+    method public boolean areContentsTheSame(T2!, T2!);
+    method public boolean areItemsTheSame(T2!, T2!);
+    method public int compare(T2!, T2!);
+    method public void dispatchLastEvent();
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public abstract static class SortedList.Callback<T2> implements java.util.Comparator<T2> androidx.recyclerview.widget.ListUpdateCallback {
+    ctor public SortedList.Callback();
+    method public abstract boolean areContentsTheSame(T2!, T2!);
+    method public abstract boolean areItemsTheSame(T2!, T2!);
+    method public abstract int compare(T2!, T2!);
+    method public Object? getChangePayload(T2!, T2!);
+    method public abstract void onChanged(int, int);
+    method public void onChanged(int, int, Object?);
+  }
+
+  public abstract class SortedListAdapterCallback<T2> extends androidx.recyclerview.widget.SortedList.Callback<T2> {
+    ctor public SortedListAdapterCallback(androidx.recyclerview.widget.RecyclerView.Adapter<?>);
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public class StaggeredGridLayoutManager extends androidx.recyclerview.widget.RecyclerView.LayoutManager implements androidx.recyclerview.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
+    ctor public StaggeredGridLayoutManager(android.content.Context!, android.util.AttributeSet!, int, int);
+    ctor public StaggeredGridLayoutManager(int, int);
+    method public android.graphics.PointF! computeScrollVectorForPosition(int);
+    method public int[]! findFirstCompletelyVisibleItemPositions(int[]!);
+    method public int[]! findFirstVisibleItemPositions(int[]!);
+    method public int[]! findLastCompletelyVisibleItemPositions(int[]!);
+    method public int[]! findLastVisibleItemPositions(int[]!);
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams! generateDefaultLayoutParams();
+    method public int getGapStrategy();
+    method public int getOrientation();
+    method public boolean getReverseLayout();
+    method public int getSpanCount();
+    method public void invalidateSpanAssignments();
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setGapStrategy(int);
+    method public void setOrientation(int);
+    method public void setReverseLayout(boolean);
+    method public void setSpanCount(int);
+    field @Deprecated public static final int GAP_HANDLING_LAZY = 1; // 0x1
+    field public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; // 0x2
+    field public static final int GAP_HANDLING_NONE = 0; // 0x0
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static class StaggeredGridLayoutManager.LayoutParams extends androidx.recyclerview.widget.RecyclerView.LayoutParams {
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public StaggeredGridLayoutManager.LayoutParams(int, int);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams!);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams!);
+    ctor public StaggeredGridLayoutManager.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public final int getSpanIndex();
+    method public boolean isFullSpan();
+    method public void setFullSpan(boolean);
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+}
+
diff --git a/recyclerview/recyclerview/api/res-1.3.0-beta01.txt b/recyclerview/recyclerview/api/res-1.3.0-beta01.txt
new file mode 100644
index 0000000..475bfc43
--- /dev/null
+++ b/recyclerview/recyclerview/api/res-1.3.0-beta01.txt
@@ -0,0 +1,9 @@
+attr fastScrollEnabled
+attr fastScrollHorizontalThumbDrawable
+attr fastScrollHorizontalTrackDrawable
+attr fastScrollVerticalThumbDrawable
+attr fastScrollVerticalTrackDrawable
+attr layoutManager
+attr reverseLayout
+attr spanCount
+attr stackFromEnd
diff --git a/recyclerview/recyclerview/api/restricted_1.3.0-beta01.txt b/recyclerview/recyclerview/api/restricted_1.3.0-beta01.txt
new file mode 100644
index 0000000..a3a2ebf
--- /dev/null
+++ b/recyclerview/recyclerview/api/restricted_1.3.0-beta01.txt
@@ -0,0 +1,1095 @@
+// Signature format: 4.0
+package androidx.recyclerview.widget {
+
+  public final class AdapterListUpdateCallback implements androidx.recyclerview.widget.ListUpdateCallback {
+    ctor public AdapterListUpdateCallback(androidx.recyclerview.widget.RecyclerView.Adapter);
+    method public void onChanged(int, int, Object?);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public final class AsyncDifferConfig<T> {
+    method public java.util.concurrent.Executor getBackgroundThreadExecutor();
+    method public androidx.recyclerview.widget.DiffUtil.ItemCallback<T!> getDiffCallback();
+  }
+
+  public static final class AsyncDifferConfig.Builder<T> {
+    ctor public AsyncDifferConfig.Builder(androidx.recyclerview.widget.DiffUtil.ItemCallback<T!>);
+    method public androidx.recyclerview.widget.AsyncDifferConfig<T!> build();
+    method public androidx.recyclerview.widget.AsyncDifferConfig.Builder<T!> setBackgroundThreadExecutor(java.util.concurrent.Executor?);
+  }
+
+  public class AsyncListDiffer<T> {
+    ctor public AsyncListDiffer(androidx.recyclerview.widget.RecyclerView.Adapter, androidx.recyclerview.widget.DiffUtil.ItemCallback<T!>);
+    ctor public AsyncListDiffer(androidx.recyclerview.widget.ListUpdateCallback, androidx.recyclerview.widget.AsyncDifferConfig<T!>);
+    method public void addListListener(androidx.recyclerview.widget.AsyncListDiffer.ListListener<T!>);
+    method public java.util.List<T!> getCurrentList();
+    method public void removeListListener(androidx.recyclerview.widget.AsyncListDiffer.ListListener<T!>);
+    method public void submitList(java.util.List<T!>?);
+    method public void submitList(java.util.List<T!>?, Runnable?);
+  }
+
+  public static interface AsyncListDiffer.ListListener<T> {
+    method public void onCurrentListChanged(java.util.List<T!>, java.util.List<T!>);
+  }
+
+  public class AsyncListUtil<T> {
+    ctor public AsyncListUtil(Class<T!>, int, androidx.recyclerview.widget.AsyncListUtil.DataCallback<T!>, androidx.recyclerview.widget.AsyncListUtil.ViewCallback);
+    method public T? getItem(int);
+    method public int getItemCount();
+    method public void onRangeChanged();
+    method public void refresh();
+  }
+
+  public abstract static class AsyncListUtil.DataCallback<T> {
+    ctor public AsyncListUtil.DataCallback();
+    method @WorkerThread public abstract void fillData(T![], int, int);
+    method @WorkerThread public int getMaxCachedTiles();
+    method @WorkerThread public void recycleData(T![], int);
+    method @WorkerThread public abstract int refreshData();
+  }
+
+  public abstract static class AsyncListUtil.ViewCallback {
+    ctor public AsyncListUtil.ViewCallback();
+    method @UiThread public void extendRangeInto(int[], int[], int);
+    method @UiThread public abstract void getItemRangeInto(int[]);
+    method @UiThread public abstract void onDataRefresh();
+    method @UiThread public abstract void onItemLoaded(int);
+    field public static final int HINT_SCROLL_ASC = 2; // 0x2
+    field public static final int HINT_SCROLL_DESC = 1; // 0x1
+    field public static final int HINT_SCROLL_NONE = 0; // 0x0
+  }
+
+  public class BatchingListUpdateCallback implements androidx.recyclerview.widget.ListUpdateCallback {
+    ctor public BatchingListUpdateCallback(androidx.recyclerview.widget.ListUpdateCallback);
+    method public void dispatchLastEvent();
+    method public void onChanged(int, int, Object?);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public final class ConcatAdapter extends androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder> {
+    ctor @java.lang.SafeVarargs public ConcatAdapter(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>!...);
+    ctor @java.lang.SafeVarargs public ConcatAdapter(androidx.recyclerview.widget.ConcatAdapter.Config, androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>!...);
+    ctor public ConcatAdapter(java.util.List<? extends androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>>);
+    ctor public ConcatAdapter(androidx.recyclerview.widget.ConcatAdapter.Config, java.util.List<? extends androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>>);
+    method public boolean addAdapter(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>);
+    method public boolean addAdapter(int, androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>);
+    method public java.util.List<? extends androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>> getAdapters();
+    method public int getItemCount();
+    method public android.util.Pair<androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>!,java.lang.Integer!> getWrappedAdapterAndPosition(int);
+    method public void onBindViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder onCreateViewHolder(android.view.ViewGroup, int);
+    method public boolean onFailedToRecycleView(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onViewAttachedToWindow(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onViewDetachedFromWindow(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onViewRecycled(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean removeAdapter(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>);
+  }
+
+  public static final class ConcatAdapter.Config {
+    field public static final androidx.recyclerview.widget.ConcatAdapter.Config DEFAULT;
+    field public final boolean isolateViewTypes;
+    field public final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode stableIdMode;
+  }
+
+  public static final class ConcatAdapter.Config.Builder {
+    ctor public ConcatAdapter.Config.Builder();
+    method public androidx.recyclerview.widget.ConcatAdapter.Config build();
+    method public androidx.recyclerview.widget.ConcatAdapter.Config.Builder setIsolateViewTypes(boolean);
+    method public androidx.recyclerview.widget.ConcatAdapter.Config.Builder setStableIdMode(androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode);
+  }
+
+  public enum ConcatAdapter.Config.StableIdMode {
+    enum_constant public static final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode ISOLATED_STABLE_IDS;
+    enum_constant public static final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode NO_STABLE_IDS;
+    enum_constant public static final androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode SHARED_STABLE_IDS;
+  }
+
+  public class DefaultItemAnimator extends androidx.recyclerview.widget.SimpleItemAnimator {
+    ctor public DefaultItemAnimator();
+    method public boolean animateAdd(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder?, int, int, int, int);
+    method public boolean animateMove(androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animateRemove(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void endAnimation(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void endAnimations();
+    method public boolean isRunning();
+    method public void runPendingAnimations();
+  }
+
+  public class DiffUtil {
+    method public static androidx.recyclerview.widget.DiffUtil.DiffResult calculateDiff(androidx.recyclerview.widget.DiffUtil.Callback);
+    method public static androidx.recyclerview.widget.DiffUtil.DiffResult calculateDiff(androidx.recyclerview.widget.DiffUtil.Callback, boolean);
+  }
+
+  public abstract static class DiffUtil.Callback {
+    ctor public DiffUtil.Callback();
+    method public abstract boolean areContentsTheSame(int, int);
+    method public abstract boolean areItemsTheSame(int, int);
+    method public Object? getChangePayload(int, int);
+    method public abstract int getNewListSize();
+    method public abstract int getOldListSize();
+  }
+
+  public static class DiffUtil.DiffResult {
+    method public int convertNewPositionToOld(@IntRange(from=0) int);
+    method public int convertOldPositionToNew(@IntRange(from=0) int);
+    method public void dispatchUpdatesTo(androidx.recyclerview.widget.RecyclerView.Adapter);
+    method public void dispatchUpdatesTo(androidx.recyclerview.widget.ListUpdateCallback);
+    field public static final int NO_POSITION = -1; // 0xffffffff
+  }
+
+  public abstract static class DiffUtil.ItemCallback<T> {
+    ctor public DiffUtil.ItemCallback();
+    method public abstract boolean areContentsTheSame(T, T);
+    method public abstract boolean areItemsTheSame(T, T);
+    method public Object? getChangePayload(T, T);
+  }
+
+  public class DividerItemDecoration extends androidx.recyclerview.widget.RecyclerView.ItemDecoration {
+    ctor public DividerItemDecoration(android.content.Context, int);
+    method public android.graphics.drawable.Drawable? getDrawable();
+    method public void setDrawable(android.graphics.drawable.Drawable);
+    method public void setOrientation(int);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public class GridLayoutManager extends androidx.recyclerview.widget.LinearLayoutManager {
+    ctor public GridLayoutManager(android.content.Context!, android.util.AttributeSet!, int, int);
+    ctor public GridLayoutManager(android.content.Context!, int);
+    ctor public GridLayoutManager(android.content.Context!, int, @androidx.recyclerview.widget.RecyclerView.Orientation int, boolean);
+    method public int getSpanCount();
+    method public androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup! getSpanSizeLookup();
+    method public boolean isUsingSpansToEstimateScrollbarDimensions();
+    method public void setSpanCount(int);
+    method public void setSpanSizeLookup(androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup!);
+    method public void setUsingSpansToEstimateScrollbarDimensions(boolean);
+    field public static final int DEFAULT_SPAN_COUNT = -1; // 0xffffffff
+  }
+
+  public static final class GridLayoutManager.DefaultSpanSizeLookup extends androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.DefaultSpanSizeLookup();
+    method public int getSpanSize(int);
+  }
+
+  public static class GridLayoutManager.LayoutParams extends androidx.recyclerview.widget.RecyclerView.LayoutParams {
+    ctor public GridLayoutManager.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public GridLayoutManager.LayoutParams(int, int);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams!);
+    ctor public GridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams!);
+    ctor public GridLayoutManager.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public int getSpanIndex();
+    method public int getSpanSize();
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+  public abstract static class GridLayoutManager.SpanSizeLookup {
+    ctor public GridLayoutManager.SpanSizeLookup();
+    method public int getSpanGroupIndex(int, int);
+    method public int getSpanIndex(int, int);
+    method public abstract int getSpanSize(int);
+    method public void invalidateSpanGroupIndexCache();
+    method public void invalidateSpanIndexCache();
+    method public boolean isSpanGroupIndexCacheEnabled();
+    method public boolean isSpanIndexCacheEnabled();
+    method public void setSpanGroupIndexCacheEnabled(boolean);
+    method public void setSpanIndexCacheEnabled(boolean);
+  }
+
+  public class ItemTouchHelper extends androidx.recyclerview.widget.RecyclerView.ItemDecoration implements androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener {
+    ctor public ItemTouchHelper(androidx.recyclerview.widget.ItemTouchHelper.Callback);
+    method public void attachToRecyclerView(androidx.recyclerview.widget.RecyclerView?);
+    method public void onChildViewAttachedToWindow(android.view.View);
+    method public void onChildViewDetachedFromWindow(android.view.View);
+    method public void startDrag(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void startSwipe(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    field public static final int ACTION_STATE_DRAG = 2; // 0x2
+    field public static final int ACTION_STATE_IDLE = 0; // 0x0
+    field public static final int ACTION_STATE_SWIPE = 1; // 0x1
+    field public static final int ANIMATION_TYPE_DRAG = 8; // 0x8
+    field public static final int ANIMATION_TYPE_SWIPE_CANCEL = 4; // 0x4
+    field public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 2; // 0x2
+    field public static final int DOWN = 2; // 0x2
+    field public static final int END = 32; // 0x20
+    field public static final int LEFT = 4; // 0x4
+    field public static final int RIGHT = 8; // 0x8
+    field public static final int START = 16; // 0x10
+    field public static final int UP = 1; // 0x1
+  }
+
+  public abstract static class ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.Callback();
+    method public boolean canDropOver(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? chooseDropTarget(androidx.recyclerview.widget.RecyclerView.ViewHolder, java.util.List<androidx.recyclerview.widget.RecyclerView.ViewHolder!>, int, int);
+    method public void clearView(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public int convertToAbsoluteDirection(int, int);
+    method public static int convertToRelativeDirection(int, int);
+    method public long getAnimationDuration(androidx.recyclerview.widget.RecyclerView, int, float, float);
+    method public int getBoundingBoxMargin();
+    method public static androidx.recyclerview.widget.ItemTouchUIUtil getDefaultUIUtil();
+    method public float getMoveThreshold(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public abstract int getMovementFlags(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public float getSwipeEscapeVelocity(float);
+    method public float getSwipeThreshold(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public float getSwipeVelocityThreshold(float);
+    method public int interpolateOutOfBoundsScroll(androidx.recyclerview.widget.RecyclerView, int, int, int, long);
+    method public boolean isItemViewSwipeEnabled();
+    method public boolean isLongPressDragEnabled();
+    method public static int makeFlag(int, int);
+    method public static int makeMovementFlags(int, int);
+    method public void onChildDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public void onChildDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, float, float, int, boolean);
+    method public abstract boolean onMove(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onMoved(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int);
+    method public void onSelectedChanged(androidx.recyclerview.widget.RecyclerView.ViewHolder?, int);
+    method public abstract void onSwiped(androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
+    field public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200; // 0xc8
+    field public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250; // 0xfa
+  }
+
+  public abstract static class ItemTouchHelper.SimpleCallback extends androidx.recyclerview.widget.ItemTouchHelper.Callback {
+    ctor public ItemTouchHelper.SimpleCallback(int, int);
+    method public int getDragDirs(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public int getMovementFlags(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public int getSwipeDirs(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void setDefaultDragDirs(int);
+    method public void setDefaultSwipeDirs(int);
+  }
+
+  public static interface ItemTouchHelper.ViewDropHandler {
+    method public void prepareForDrop(android.view.View, android.view.View, int, int);
+  }
+
+  public interface ItemTouchUIUtil {
+    method public void clearView(android.view.View);
+    method public void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, android.view.View, float, float, int, boolean);
+    method public void onSelected(android.view.View);
+  }
+
+  public class LinearLayoutManager extends androidx.recyclerview.widget.RecyclerView.LayoutManager implements androidx.recyclerview.widget.ItemTouchHelper.ViewDropHandler androidx.recyclerview.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
+    ctor public LinearLayoutManager(android.content.Context);
+    ctor public LinearLayoutManager(android.content.Context, @androidx.recyclerview.widget.RecyclerView.Orientation int, boolean);
+    ctor public LinearLayoutManager(android.content.Context, android.util.AttributeSet?, int, int);
+    method protected void calculateExtraLayoutSpace(androidx.recyclerview.widget.RecyclerView.State, int[]);
+    method public android.graphics.PointF? computeScrollVectorForPosition(int);
+    method public int findFirstCompletelyVisibleItemPosition();
+    method public int findFirstVisibleItemPosition();
+    method public int findLastCompletelyVisibleItemPosition();
+    method public int findLastVisibleItemPosition();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method @Deprecated protected int getExtraLayoutSpace(androidx.recyclerview.widget.RecyclerView.State!);
+    method public int getInitialPrefetchItemCount();
+    method @androidx.recyclerview.widget.RecyclerView.Orientation public int getOrientation();
+    method public boolean getRecycleChildrenOnDetach();
+    method public boolean getReverseLayout();
+    method public boolean getStackFromEnd();
+    method protected boolean isLayoutRTL();
+    method public boolean isSmoothScrollbarEnabled();
+    method public void prepareForDrop(android.view.View, android.view.View, int, int);
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setInitialPrefetchItemCount(int);
+    method public void setOrientation(@androidx.recyclerview.widget.RecyclerView.Orientation int);
+    method public void setRecycleChildrenOnDetach(boolean);
+    method public void setReverseLayout(boolean);
+    method public void setSmoothScrollbarEnabled(boolean);
+    method public void setStackFromEnd(boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_OFFSET = -2147483648; // 0x80000000
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  protected static class LinearLayoutManager.LayoutChunkResult {
+    ctor protected LinearLayoutManager.LayoutChunkResult();
+    field public int mConsumed;
+    field public boolean mFinished;
+    field public boolean mFocusable;
+    field public boolean mIgnoreConsumed;
+  }
+
+  public class LinearSmoothScroller extends androidx.recyclerview.widget.RecyclerView.SmoothScroller {
+    ctor public LinearSmoothScroller(android.content.Context);
+    method public int calculateDtToFit(int, int, int, int, int);
+    method public int calculateDxToMakeVisible(android.view.View, int);
+    method public int calculateDyToMakeVisible(android.view.View, int);
+    method protected float calculateSpeedPerPixel(android.util.DisplayMetrics);
+    method protected int calculateTimeForDeceleration(int);
+    method protected int calculateTimeForScrolling(int);
+    method protected int getHorizontalSnapPreference();
+    method protected int getVerticalSnapPreference();
+    method protected void onSeekTargetStep(int, int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method protected void onStart();
+    method protected void onStop();
+    method protected void onTargetFound(android.view.View, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method protected void updateActionForInterimTarget(androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    field public static final int SNAP_TO_ANY = 0; // 0x0
+    field public static final int SNAP_TO_END = 1; // 0x1
+    field public static final int SNAP_TO_START = -1; // 0xffffffff
+    field protected final android.view.animation.DecelerateInterpolator! mDecelerateInterpolator;
+    field protected int mInterimTargetDx;
+    field protected int mInterimTargetDy;
+    field protected final android.view.animation.LinearInterpolator! mLinearInterpolator;
+    field protected android.graphics.PointF? mTargetVector;
+  }
+
+  public class LinearSnapHelper extends androidx.recyclerview.widget.SnapHelper {
+    ctor public LinearSnapHelper();
+    method public int[]! calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
+    method public android.view.View! findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager!);
+    method public int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager!, int, int);
+  }
+
+  public abstract class ListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
+    ctor protected ListAdapter(androidx.recyclerview.widget.DiffUtil.ItemCallback<T!>);
+    ctor protected ListAdapter(androidx.recyclerview.widget.AsyncDifferConfig<T!>);
+    method public java.util.List<T!> getCurrentList();
+    method protected T! getItem(int);
+    method public int getItemCount();
+    method public void onCurrentListChanged(java.util.List<T!>, java.util.List<T!>);
+    method public void submitList(java.util.List<T!>?);
+    method public void submitList(java.util.List<T!>?, Runnable?);
+  }
+
+  public interface ListUpdateCallback {
+    method public void onChanged(int, int, Object?);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public abstract class OrientationHelper {
+    method public static androidx.recyclerview.widget.OrientationHelper! createHorizontalHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager!);
+    method public static androidx.recyclerview.widget.OrientationHelper! createOrientationHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager!, @androidx.recyclerview.widget.RecyclerView.Orientation int);
+    method public static androidx.recyclerview.widget.OrientationHelper! createVerticalHelper(androidx.recyclerview.widget.RecyclerView.LayoutManager!);
+    method public abstract int getDecoratedEnd(android.view.View!);
+    method public abstract int getDecoratedMeasurement(android.view.View!);
+    method public abstract int getDecoratedMeasurementInOther(android.view.View!);
+    method public abstract int getDecoratedStart(android.view.View!);
+    method public abstract int getEnd();
+    method public abstract int getEndAfterPadding();
+    method public abstract int getEndPadding();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutManager! getLayoutManager();
+    method public abstract int getMode();
+    method public abstract int getModeInOther();
+    method public abstract int getStartAfterPadding();
+    method public abstract int getTotalSpace();
+    method public int getTotalSpaceChange();
+    method public abstract int getTransformedEndWithDecoration(android.view.View!);
+    method public abstract int getTransformedStartWithDecoration(android.view.View!);
+    method public abstract void offsetChild(android.view.View!, int);
+    method public abstract void offsetChildren(int);
+    method public void onLayoutComplete();
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+    field protected final androidx.recyclerview.widget.RecyclerView.LayoutManager! mLayoutManager;
+  }
+
+  public class PagerSnapHelper extends androidx.recyclerview.widget.SnapHelper {
+    ctor public PagerSnapHelper();
+    method public int[]? calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
+    method public android.view.View? findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method public int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager, int, int);
+  }
+
+  public class RecyclerView extends android.view.ViewGroup implements androidx.core.view.NestedScrollingChild2 androidx.core.view.NestedScrollingChild3 androidx.core.view.ScrollingView {
+    ctor public RecyclerView(android.content.Context);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet?);
+    ctor public RecyclerView(android.content.Context, android.util.AttributeSet?, int);
+    method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration, int);
+    method public void addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
+    method public void addOnChildAttachStateChangeListener(androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void addOnItemTouchListener(androidx.recyclerview.widget.RecyclerView.OnItemTouchListener);
+    method public void addOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener);
+    method public void addRecyclerListener(androidx.recyclerview.widget.RecyclerView.RecyclerListener);
+    method public void clearOnChildAttachStateChangeListeners();
+    method public void clearOnScrollListeners();
+    method public int computeHorizontalScrollExtent();
+    method public int computeHorizontalScrollOffset();
+    method public int computeHorizontalScrollRange();
+    method public int computeVerticalScrollExtent();
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
+    method public boolean dispatchNestedPreScroll(int, int, int[]!, int[]!, int);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]!, int);
+    method public final void dispatchNestedScroll(int, int, int, int, int[]!, int, int[]);
+    method public boolean drawChild(android.graphics.Canvas!, android.view.View!, long);
+    method public android.view.View? findChildViewUnder(float, float);
+    method public android.view.View? findContainingItemView(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? findContainingViewHolder(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? findViewHolderForAdapterPosition(int);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder! findViewHolderForItemId(long);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? findViewHolderForLayoutPosition(int);
+    method @Deprecated public androidx.recyclerview.widget.RecyclerView.ViewHolder? findViewHolderForPosition(int);
+    method public boolean fling(int, int);
+    method public androidx.recyclerview.widget.RecyclerView.Adapter? getAdapter();
+    method public int getChildAdapterPosition(android.view.View);
+    method public long getChildItemId(android.view.View);
+    method public int getChildLayoutPosition(android.view.View);
+    method @Deprecated public int getChildPosition(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder! getChildViewHolder(android.view.View);
+    method public androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate? getCompatAccessibilityDelegate();
+    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
+    method public androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory getEdgeEffectFactory();
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator? getItemAnimator();
+    method public androidx.recyclerview.widget.RecyclerView.ItemDecoration getItemDecorationAt(int);
+    method public int getItemDecorationCount();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutManager? getLayoutManager();
+    method public int getMaxFlingVelocity();
+    method public int getMinFlingVelocity();
+    method public androidx.recyclerview.widget.RecyclerView.OnFlingListener? getOnFlingListener();
+    method public boolean getPreserveFocusAfterLayout();
+    method public androidx.recyclerview.widget.RecyclerView.RecycledViewPool getRecycledViewPool();
+    method public int getScrollState();
+    method public boolean hasFixedSize();
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean hasPendingAdapterUpdates();
+    method public void invalidateItemDecorations();
+    method public boolean isAnimating();
+    method public boolean isComputingLayout();
+    method @Deprecated public boolean isLayoutFrozen();
+    method public final boolean isLayoutSuppressed();
+    method public void nestedScrollBy(int, int);
+    method public void offsetChildrenHorizontal(@Px int);
+    method public void offsetChildrenVertical(@Px int);
+    method public void onChildAttachedToWindow(android.view.View);
+    method public void onChildDetachedFromWindow(android.view.View);
+    method public void onDraw(android.graphics.Canvas!);
+    method public void onScrollStateChanged(int);
+    method public void onScrolled(@Px int, @Px int);
+    method public void removeItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration);
+    method public void removeItemDecorationAt(int);
+    method public void removeOnChildAttachStateChangeListener(androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener);
+    method public void removeOnItemTouchListener(androidx.recyclerview.widget.RecyclerView.OnItemTouchListener);
+    method public void removeOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener);
+    method public void removeRecyclerListener(androidx.recyclerview.widget.RecyclerView.RecyclerListener);
+    method public void scrollToPosition(int);
+    method public void setAccessibilityDelegateCompat(androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate?);
+    method public void setAdapter(androidx.recyclerview.widget.RecyclerView.Adapter?);
+    method public void setChildDrawingOrderCallback(androidx.recyclerview.widget.RecyclerView.ChildDrawingOrderCallback?);
+    method public void setEdgeEffectFactory(androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory);
+    method public void setHasFixedSize(boolean);
+    method public void setItemAnimator(androidx.recyclerview.widget.RecyclerView.ItemAnimator?);
+    method public void setItemViewCacheSize(int);
+    method @Deprecated public void setLayoutFrozen(boolean);
+    method public void setLayoutManager(androidx.recyclerview.widget.RecyclerView.LayoutManager?);
+    method @Deprecated public void setLayoutTransition(android.animation.LayoutTransition!);
+    method public void setOnFlingListener(androidx.recyclerview.widget.RecyclerView.OnFlingListener?);
+    method @Deprecated public void setOnScrollListener(androidx.recyclerview.widget.RecyclerView.OnScrollListener?);
+    method public void setPreserveFocusAfterLayout(boolean);
+    method public void setRecycledViewPool(androidx.recyclerview.widget.RecyclerView.RecycledViewPool?);
+    method @Deprecated public void setRecyclerListener(androidx.recyclerview.widget.RecyclerView.RecyclerListener?);
+    method public void setScrollingTouchSlop(int);
+    method public void setViewCacheExtension(androidx.recyclerview.widget.RecyclerView.ViewCacheExtension?);
+    method public void smoothScrollBy(@Px int, @Px int);
+    method public void smoothScrollBy(@Px int, @Px int, android.view.animation.Interpolator?);
+    method public void smoothScrollBy(@Px int, @Px int, android.view.animation.Interpolator?, int);
+    method public void smoothScrollToPosition(int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll(int);
+    method public void stopScroll();
+    method public final void suppressLayout(boolean);
+    method public void swapAdapter(androidx.recyclerview.widget.RecyclerView.Adapter?, boolean);
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int INVALID_TYPE = -1; // 0xffffffff
+    field public static final long NO_ID = -1L; // 0xffffffffffffffffL
+    field public static final int NO_POSITION = -1; // 0xffffffff
+    field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
+    field public static final int SCROLL_STATE_IDLE = 0; // 0x0
+    field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
+    field public static final int TOUCH_SLOP_DEFAULT = 0; // 0x0
+    field public static final int TOUCH_SLOP_PAGING = 1; // 0x1
+    field public static final int UNDEFINED_DURATION = -2147483648; // 0x80000000
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public abstract static class RecyclerView.Adapter<VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> {
+    ctor public RecyclerView.Adapter();
+    method public final void bindViewHolder(VH, int);
+    method public final VH createViewHolder(android.view.ViewGroup, int);
+    method public int findRelativeAdapterPositionIn(androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>, androidx.recyclerview.widget.RecyclerView.ViewHolder, int);
+    method public abstract int getItemCount();
+    method public long getItemId(int);
+    method public int getItemViewType(int);
+    method public final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy getStateRestorationPolicy();
+    method public final boolean hasObservers();
+    method public final boolean hasStableIds();
+    method public final void notifyDataSetChanged();
+    method public final void notifyItemChanged(int);
+    method public final void notifyItemChanged(int, Object?);
+    method public final void notifyItemInserted(int);
+    method public final void notifyItemMoved(int, int);
+    method public final void notifyItemRangeChanged(int, int);
+    method public final void notifyItemRangeChanged(int, int, Object?);
+    method public final void notifyItemRangeInserted(int, int);
+    method public final void notifyItemRangeRemoved(int, int);
+    method public final void notifyItemRemoved(int);
+    method public void onAttachedToRecyclerView(androidx.recyclerview.widget.RecyclerView);
+    method public abstract void onBindViewHolder(VH, int);
+    method public void onBindViewHolder(VH, int, java.util.List<java.lang.Object!>);
+    method public abstract VH onCreateViewHolder(android.view.ViewGroup, int);
+    method public void onDetachedFromRecyclerView(androidx.recyclerview.widget.RecyclerView);
+    method public boolean onFailedToRecycleView(VH);
+    method public void onViewAttachedToWindow(VH);
+    method public void onViewDetachedFromWindow(VH);
+    method public void onViewRecycled(VH);
+    method public void registerAdapterDataObserver(androidx.recyclerview.widget.RecyclerView.AdapterDataObserver);
+    method public void setHasStableIds(boolean);
+    method public void setStateRestorationPolicy(androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy);
+    method public void unregisterAdapterDataObserver(androidx.recyclerview.widget.RecyclerView.AdapterDataObserver);
+  }
+
+  public enum RecyclerView.Adapter.StateRestorationPolicy {
+    enum_constant public static final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy ALLOW;
+    enum_constant public static final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy PREVENT;
+    enum_constant public static final androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy PREVENT_WHEN_EMPTY;
+  }
+
+  public abstract static class RecyclerView.AdapterDataObserver {
+    ctor public RecyclerView.AdapterDataObserver();
+    method public void onChanged();
+    method public void onItemRangeChanged(int, int);
+    method public void onItemRangeChanged(int, int, Object?);
+    method public void onItemRangeInserted(int, int);
+    method public void onItemRangeMoved(int, int, int);
+    method public void onItemRangeRemoved(int, int);
+    method public void onStateRestorationPolicyChanged();
+  }
+
+  public static interface RecyclerView.ChildDrawingOrderCallback {
+    method public int onGetChildDrawingOrder(int, int);
+  }
+
+  public static class RecyclerView.EdgeEffectFactory {
+    ctor public RecyclerView.EdgeEffectFactory();
+    method protected android.widget.EdgeEffect createEdgeEffect(androidx.recyclerview.widget.RecyclerView, @androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.EdgeDirection int);
+    field public static final int DIRECTION_BOTTOM = 3; // 0x3
+    field public static final int DIRECTION_LEFT = 0; // 0x0
+    field public static final int DIRECTION_RIGHT = 2; // 0x2
+    field public static final int DIRECTION_TOP = 1; // 0x1
+  }
+
+  @IntDef({androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_LEFT, androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_TOP, androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_RIGHT, androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory.DIRECTION_BOTTOM}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RecyclerView.EdgeEffectFactory.EdgeDirection {
+  }
+
+  public abstract static class RecyclerView.ItemAnimator {
+    ctor public RecyclerView.ItemAnimator();
+    method public abstract boolean animateAppearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateDisappearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?);
+    method public abstract boolean animatePersistence(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean canReuseUpdatedViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean canReuseUpdatedViewHolder(androidx.recyclerview.widget.RecyclerView.ViewHolder, java.util.List<java.lang.Object!>);
+    method public final void dispatchAnimationFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationStarted(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAnimationsFinished();
+    method public abstract void endAnimation(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public abstract void endAnimations();
+    method public long getAddDuration();
+    method public long getChangeDuration();
+    method public long getMoveDuration();
+    method public long getRemoveDuration();
+    method public abstract boolean isRunning();
+    method public final boolean isRunning(androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemAnimatorFinishedListener?);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo obtainHolderInfo();
+    method public void onAnimationFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public void onAnimationStarted(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPostLayoutInformation(androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo recordPreLayoutInformation(androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.ViewHolder, @androidx.recyclerview.widget.RecyclerView.ItemAnimator.AdapterChanges int, java.util.List<java.lang.Object!>);
+    method public abstract void runPendingAnimations();
+    method public void setAddDuration(long);
+    method public void setChangeDuration(long);
+    method public void setMoveDuration(long);
+    method public void setRemoveDuration(long);
+    field public static final int FLAG_APPEARED_IN_PRE_LAYOUT = 4096; // 0x1000
+    field public static final int FLAG_CHANGED = 2; // 0x2
+    field public static final int FLAG_INVALIDATED = 4; // 0x4
+    field public static final int FLAG_MOVED = 2048; // 0x800
+    field public static final int FLAG_REMOVED = 8; // 0x8
+  }
+
+  @IntDef(flag=true, value={androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_CHANGED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_REMOVED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_MOVED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_INVALIDATED, androidx.recyclerview.widget.RecyclerView.ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RecyclerView.ItemAnimator.AdapterChanges {
+  }
+
+  public static interface RecyclerView.ItemAnimator.ItemAnimatorFinishedListener {
+    method public void onAnimationsFinished();
+  }
+
+  public static class RecyclerView.ItemAnimator.ItemHolderInfo {
+    ctor public RecyclerView.ItemAnimator.ItemHolderInfo();
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo setFrom(androidx.recyclerview.widget.RecyclerView.ViewHolder, @androidx.recyclerview.widget.RecyclerView.ItemAnimator.AdapterChanges int);
+    field public int bottom;
+    field @androidx.recyclerview.widget.RecyclerView.ItemAnimator.AdapterChanges public int changeFlags;
+    field public int left;
+    field public int right;
+    field public int top;
+  }
+
+  public abstract static class RecyclerView.ItemDecoration {
+    ctor public RecyclerView.ItemDecoration();
+    method @Deprecated public void getItemOffsets(android.graphics.Rect, int, androidx.recyclerview.widget.RecyclerView);
+    method public void getItemOffsets(android.graphics.Rect, android.view.View, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
+    method public void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
+    method @Deprecated public void onDraw(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView);
+    method public void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State);
+    method @Deprecated public void onDrawOver(android.graphics.Canvas, androidx.recyclerview.widget.RecyclerView);
+  }
+
+  public abstract static class RecyclerView.LayoutManager {
+    ctor public RecyclerView.LayoutManager();
+    method public void addDisappearingView(android.view.View!);
+    method public void addDisappearingView(android.view.View!, int);
+    method public void addView(android.view.View!);
+    method public void addView(android.view.View!, int);
+    method public void assertInLayoutOrScroll(String!);
+    method public void assertNotInLayoutOrScroll(String?);
+    method public void attachView(android.view.View, int, androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public void attachView(android.view.View, int);
+    method public void attachView(android.view.View);
+    method public void calculateItemDecorationsForChild(android.view.View, android.graphics.Rect);
+    method public boolean canScrollHorizontally();
+    method public boolean canScrollVertically();
+    method public boolean checkLayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public static int chooseSize(int, int, int);
+    method public void collectAdjacentPrefetchPositions(int, int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
+    method public void collectInitialPrefetchPositions(int, androidx.recyclerview.widget.RecyclerView.LayoutManager.LayoutPrefetchRegistry);
+    method public int computeHorizontalScrollExtent(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeHorizontalScrollOffset(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeHorizontalScrollRange(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeVerticalScrollExtent(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeVerticalScrollOffset(androidx.recyclerview.widget.RecyclerView.State);
+    method public int computeVerticalScrollRange(androidx.recyclerview.widget.RecyclerView.State);
+    method public void detachAndScrapAttachedViews(androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void detachAndScrapView(android.view.View, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void detachAndScrapViewAt(int, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void detachView(android.view.View);
+    method public void detachViewAt(int);
+    method public void endAnimation(android.view.View!);
+    method public android.view.View? findContainingItemView(android.view.View);
+    method public android.view.View? findViewByPosition(int);
+    method public abstract androidx.recyclerview.widget.RecyclerView.LayoutParams generateDefaultLayoutParams();
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams! generateLayoutParams(android.view.ViewGroup.LayoutParams!);
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams! generateLayoutParams(android.content.Context!, android.util.AttributeSet!);
+    method public int getBaseline();
+    method public int getBottomDecorationHeight(android.view.View);
+    method public android.view.View? getChildAt(int);
+    method public int getChildCount();
+    method @Deprecated public static int getChildMeasureSpec(int, int, int, boolean);
+    method public static int getChildMeasureSpec(int, int, int, int, boolean);
+    method public boolean getClipToPadding();
+    method public int getColumnCountForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public int getDecoratedBottom(android.view.View);
+    method public void getDecoratedBoundsWithMargins(android.view.View, android.graphics.Rect);
+    method public int getDecoratedLeft(android.view.View);
+    method public int getDecoratedMeasuredHeight(android.view.View);
+    method public int getDecoratedMeasuredWidth(android.view.View);
+    method public int getDecoratedRight(android.view.View);
+    method public int getDecoratedTop(android.view.View);
+    method public android.view.View? getFocusedChild();
+    method @Px public int getHeight();
+    method public int getHeightMode();
+    method public int getItemCount();
+    method public int getItemViewType(android.view.View);
+    method public int getLayoutDirection();
+    method public int getLeftDecorationWidth(android.view.View);
+    method @Px public int getMinimumHeight();
+    method @Px public int getMinimumWidth();
+    method @Px public int getPaddingBottom();
+    method @Px public int getPaddingEnd();
+    method @Px public int getPaddingLeft();
+    method @Px public int getPaddingRight();
+    method @Px public int getPaddingStart();
+    method @Px public int getPaddingTop();
+    method public int getPosition(android.view.View);
+    method public static androidx.recyclerview.widget.RecyclerView.LayoutManager.Properties! getProperties(android.content.Context, android.util.AttributeSet?, int, int);
+    method public int getRightDecorationWidth(android.view.View);
+    method public int getRowCountForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public int getSelectionModeForAccessibility(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public int getTopDecorationHeight(android.view.View);
+    method public void getTransformedBoundingBox(android.view.View, boolean, android.graphics.Rect);
+    method @Px public int getWidth();
+    method public int getWidthMode();
+    method public boolean hasFocus();
+    method public void ignoreView(android.view.View);
+    method public boolean isAttachedToWindow();
+    method public boolean isAutoMeasureEnabled();
+    method public boolean isFocused();
+    method public final boolean isItemPrefetchEnabled();
+    method public boolean isLayoutHierarchical(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public boolean isMeasurementCacheEnabled();
+    method public boolean isSmoothScrolling();
+    method public boolean isViewPartiallyVisible(android.view.View, boolean, boolean);
+    method public void layoutDecorated(android.view.View, int, int, int, int);
+    method public void layoutDecoratedWithMargins(android.view.View, int, int, int, int);
+    method public void measureChild(android.view.View, int, int);
+    method public void measureChildWithMargins(android.view.View, int, int);
+    method public void moveView(int, int);
+    method public void offsetChildrenHorizontal(@Px int);
+    method public void offsetChildrenVertical(@Px int);
+    method public void onAdapterChanged(androidx.recyclerview.widget.RecyclerView.Adapter?, androidx.recyclerview.widget.RecyclerView.Adapter?);
+    method public boolean onAddFocusables(androidx.recyclerview.widget.RecyclerView, java.util.ArrayList<android.view.View!>, int, int);
+    method @CallSuper public void onAttachedToWindow(androidx.recyclerview.widget.RecyclerView!);
+    method @Deprecated public void onDetachedFromWindow(androidx.recyclerview.widget.RecyclerView!);
+    method @CallSuper public void onDetachedFromWindow(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public android.view.View? onFocusSearchFailed(android.view.View, int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityEvent(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+    method public void onInitializeAccessibilityNodeInfoForItem(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat);
+    method public android.view.View? onInterceptFocusSearch(android.view.View, int);
+    method public void onItemsAdded(androidx.recyclerview.widget.RecyclerView, int, int);
+    method public void onItemsChanged(androidx.recyclerview.widget.RecyclerView);
+    method public void onItemsMoved(androidx.recyclerview.widget.RecyclerView, int, int, int);
+    method public void onItemsRemoved(androidx.recyclerview.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(androidx.recyclerview.widget.RecyclerView, int, int);
+    method public void onItemsUpdated(androidx.recyclerview.widget.RecyclerView, int, int, Object?);
+    method public void onLayoutChildren(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public void onLayoutCompleted(androidx.recyclerview.widget.RecyclerView.State);
+    method public void onMeasure(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, int, int);
+    method @Deprecated public boolean onRequestChildFocus(androidx.recyclerview.widget.RecyclerView, android.view.View, android.view.View?);
+    method public boolean onRequestChildFocus(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State, android.view.View, android.view.View?);
+    method public void onRestoreInstanceState(android.os.Parcelable);
+    method public android.os.Parcelable? onSaveInstanceState();
+    method public void onScrollStateChanged(int);
+    method public boolean performAccessibilityAction(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, int, android.os.Bundle?);
+    method public boolean performAccessibilityActionForItem(androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State, android.view.View, int, android.os.Bundle?);
+    method public void postOnAnimation(Runnable!);
+    method public void removeAllViews();
+    method public void removeAndRecycleAllViews(androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleView(android.view.View, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public void removeAndRecycleViewAt(int, androidx.recyclerview.widget.RecyclerView.Recycler);
+    method public boolean removeCallbacks(Runnable!);
+    method public void removeDetachedView(android.view.View);
+    method public void removeView(android.view.View!);
+    method public void removeViewAt(int);
+    method public boolean requestChildRectangleOnScreen(androidx.recyclerview.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean);
+    method public boolean requestChildRectangleOnScreen(androidx.recyclerview.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean, boolean);
+    method public void requestLayout();
+    method public void requestSimpleAnimationsInNextLayout();
+    method public int scrollHorizontallyBy(int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method public void scrollToPosition(int);
+    method public int scrollVerticallyBy(int, androidx.recyclerview.widget.RecyclerView.Recycler, androidx.recyclerview.widget.RecyclerView.State);
+    method @Deprecated public void setAutoMeasureEnabled(boolean);
+    method public final void setItemPrefetchEnabled(boolean);
+    method public void setMeasuredDimension(android.graphics.Rect!, int, int);
+    method public void setMeasuredDimension(int, int);
+    method public void setMeasurementCacheEnabled(boolean);
+    method public void smoothScrollToPosition(androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.widget.RecyclerView.State, int);
+    method public void startSmoothScroll(androidx.recyclerview.widget.RecyclerView.SmoothScroller!);
+    method public void stopIgnoringView(android.view.View);
+    method public boolean supportsPredictiveItemAnimations();
+  }
+
+  public static interface RecyclerView.LayoutManager.LayoutPrefetchRegistry {
+    method public void addPosition(int, int);
+  }
+
+  public static class RecyclerView.LayoutManager.Properties {
+    ctor public RecyclerView.LayoutManager.Properties();
+    field public int orientation;
+    field public boolean reverseLayout;
+    field public int spanCount;
+    field public boolean stackFromEnd;
+  }
+
+  public static class RecyclerView.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public RecyclerView.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public RecyclerView.LayoutParams(int, int);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.MarginLayoutParams!);
+    ctor public RecyclerView.LayoutParams(android.view.ViewGroup.LayoutParams!);
+    ctor public RecyclerView.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public int getAbsoluteAdapterPosition();
+    method public int getBindingAdapterPosition();
+    method @Deprecated public int getViewAdapterPosition();
+    method public int getViewLayoutPosition();
+    method @Deprecated public int getViewPosition();
+    method public boolean isItemChanged();
+    method public boolean isItemRemoved();
+    method public boolean isViewInvalid();
+    method public boolean viewNeedsUpdate();
+  }
+
+  public static interface RecyclerView.OnChildAttachStateChangeListener {
+    method public void onChildViewAttachedToWindow(android.view.View);
+    method public void onChildViewDetachedFromWindow(android.view.View);
+  }
+
+  public abstract static class RecyclerView.OnFlingListener {
+    ctor public RecyclerView.OnFlingListener();
+    method public abstract boolean onFling(int, int);
+  }
+
+  public static interface RecyclerView.OnItemTouchListener {
+    method public boolean onInterceptTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+    method public void onRequestDisallowInterceptTouchEvent(boolean);
+    method public void onTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public abstract static class RecyclerView.OnScrollListener {
+    ctor public RecyclerView.OnScrollListener();
+    method public void onScrollStateChanged(androidx.recyclerview.widget.RecyclerView, int);
+    method public void onScrolled(androidx.recyclerview.widget.RecyclerView, int, int);
+  }
+
+  @IntDef({androidx.recyclerview.widget.RecyclerView.HORIZONTAL, androidx.recyclerview.widget.RecyclerView.VERTICAL}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RecyclerView.Orientation {
+  }
+
+  public static class RecyclerView.RecycledViewPool {
+    ctor public RecyclerView.RecycledViewPool();
+    method public void clear();
+    method public androidx.recyclerview.widget.RecyclerView.ViewHolder? getRecycledView(int);
+    method public int getRecycledViewCount(int);
+    method public void putRecycledView(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void setMaxRecycledViews(int, int);
+  }
+
+  public final class RecyclerView.Recycler {
+    ctor public RecyclerView.Recycler();
+    method public void bindViewToPosition(android.view.View, int);
+    method public void clear();
+    method public int convertPreLayoutPositionToPostLayout(int);
+    method public java.util.List<androidx.recyclerview.widget.RecyclerView.ViewHolder!> getScrapList();
+    method public android.view.View getViewForPosition(int);
+    method public void recycleView(android.view.View);
+    method public void setViewCacheSize(int);
+  }
+
+  public static interface RecyclerView.RecyclerListener {
+    method public void onViewRecycled(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+  }
+
+  public static class RecyclerView.SimpleOnItemTouchListener implements androidx.recyclerview.widget.RecyclerView.OnItemTouchListener {
+    ctor public RecyclerView.SimpleOnItemTouchListener();
+    method public boolean onInterceptTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+    method public void onRequestDisallowInterceptTouchEvent(boolean);
+    method public void onTouchEvent(androidx.recyclerview.widget.RecyclerView, android.view.MotionEvent);
+  }
+
+  public abstract static class RecyclerView.SmoothScroller {
+    ctor public RecyclerView.SmoothScroller();
+    method public android.graphics.PointF? computeScrollVectorForPosition(int);
+    method public android.view.View! findViewByPosition(int);
+    method public int getChildCount();
+    method public int getChildPosition(android.view.View!);
+    method public androidx.recyclerview.widget.RecyclerView.LayoutManager? getLayoutManager();
+    method public int getTargetPosition();
+    method @Deprecated public void instantScrollToPosition(int);
+    method public boolean isPendingInitialRun();
+    method public boolean isRunning();
+    method protected void normalize(android.graphics.PointF);
+    method protected void onChildAttachedToWindow(android.view.View!);
+    method protected abstract void onSeekTargetStep(@Px int, @Px int, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method protected abstract void onStart();
+    method protected abstract void onStop();
+    method protected abstract void onTargetFound(android.view.View, androidx.recyclerview.widget.RecyclerView.State, androidx.recyclerview.widget.RecyclerView.SmoothScroller.Action);
+    method public void setTargetPosition(int);
+    method protected final void stop();
+  }
+
+  public static class RecyclerView.SmoothScroller.Action {
+    ctor public RecyclerView.SmoothScroller.Action(@Px int, @Px int);
+    ctor public RecyclerView.SmoothScroller.Action(@Px int, @Px int, int);
+    ctor public RecyclerView.SmoothScroller.Action(@Px int, @Px int, int, android.view.animation.Interpolator?);
+    method public int getDuration();
+    method @Px public int getDx();
+    method @Px public int getDy();
+    method public android.view.animation.Interpolator? getInterpolator();
+    method public void jumpTo(int);
+    method public void setDuration(int);
+    method public void setDx(@Px int);
+    method public void setDy(@Px int);
+    method public void setInterpolator(android.view.animation.Interpolator?);
+    method public void update(@Px int, @Px int, int, android.view.animation.Interpolator?);
+    field public static final int UNDEFINED_DURATION = -2147483648; // 0x80000000
+  }
+
+  public static interface RecyclerView.SmoothScroller.ScrollVectorProvider {
+    method public android.graphics.PointF? computeScrollVectorForPosition(int);
+  }
+
+  public static class RecyclerView.State {
+    ctor public RecyclerView.State();
+    method public boolean didStructureChange();
+    method public <T> T! get(int);
+    method public int getItemCount();
+    method public int getRemainingScrollHorizontal();
+    method public int getRemainingScrollVertical();
+    method public int getTargetScrollPosition();
+    method public boolean hasTargetScrollPosition();
+    method public boolean isMeasuring();
+    method public boolean isPreLayout();
+    method public void put(int, Object!);
+    method public void remove(int);
+    method public boolean willRunPredictiveAnimations();
+    method public boolean willRunSimpleAnimations();
+  }
+
+  public abstract static class RecyclerView.ViewCacheExtension {
+    ctor public RecyclerView.ViewCacheExtension();
+    method public abstract android.view.View? getViewForPositionAndType(androidx.recyclerview.widget.RecyclerView.Recycler, int, int);
+  }
+
+  public abstract static class RecyclerView.ViewHolder {
+    ctor public RecyclerView.ViewHolder(android.view.View);
+    method public final int getAbsoluteAdapterPosition();
+    method @Deprecated public final int getAdapterPosition();
+    method public final androidx.recyclerview.widget.RecyclerView.Adapter<? extends androidx.recyclerview.widget.RecyclerView.ViewHolder>? getBindingAdapter();
+    method public final int getBindingAdapterPosition();
+    method public final long getItemId();
+    method public final int getItemViewType();
+    method public final int getLayoutPosition();
+    method public final int getOldPosition();
+    method @Deprecated public final int getPosition();
+    method public final boolean isRecyclable();
+    method public final void setIsRecyclable(boolean);
+    field public final android.view.View itemView;
+  }
+
+  public class RecyclerViewAccessibilityDelegate extends androidx.core.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate(androidx.recyclerview.widget.RecyclerView);
+    method public androidx.core.view.AccessibilityDelegateCompat getItemDelegate();
+  }
+
+  public static class RecyclerViewAccessibilityDelegate.ItemDelegate extends androidx.core.view.AccessibilityDelegateCompat {
+    ctor public RecyclerViewAccessibilityDelegate.ItemDelegate(androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate);
+  }
+
+  public abstract class SimpleItemAnimator extends androidx.recyclerview.widget.RecyclerView.ItemAnimator {
+    ctor public SimpleItemAnimator();
+    method public abstract boolean animateAdd(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public boolean animateAppearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateChange(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ViewHolder?, int, int, int, int);
+    method public boolean animateDisappearance(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo?);
+    method public abstract boolean animateMove(androidx.recyclerview.widget.RecyclerView.ViewHolder, int, int, int, int);
+    method public boolean animatePersistence(androidx.recyclerview.widget.RecyclerView.ViewHolder, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo, androidx.recyclerview.widget.RecyclerView.ItemAnimator.ItemHolderInfo);
+    method public abstract boolean animateRemove(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchAddFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchAddStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchChangeFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public final void dispatchChangeStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public final void dispatchMoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchMoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public final void dispatchRemoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder);
+    method public final void dispatchRemoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public boolean getSupportsChangeAnimations();
+    method public void onAddFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onAddStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onChangeFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public void onChangeStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!, boolean);
+    method public void onMoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onMoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onRemoveFinished(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void onRemoveStarting(androidx.recyclerview.widget.RecyclerView.ViewHolder!);
+    method public void setSupportsChangeAnimations(boolean);
+  }
+
+  public abstract class SnapHelper extends androidx.recyclerview.widget.RecyclerView.OnFlingListener {
+    ctor public SnapHelper();
+    method public void attachToRecyclerView(androidx.recyclerview.widget.RecyclerView?) throws java.lang.IllegalStateException;
+    method public abstract int[]? calculateDistanceToFinalSnap(androidx.recyclerview.widget.RecyclerView.LayoutManager, android.view.View);
+    method public int[] calculateScrollDistance(int, int);
+    method protected androidx.recyclerview.widget.RecyclerView.SmoothScroller? createScroller(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method @Deprecated protected androidx.recyclerview.widget.LinearSmoothScroller? createSnapScroller(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method public abstract android.view.View? findSnapView(androidx.recyclerview.widget.RecyclerView.LayoutManager);
+    method public abstract int findTargetSnapPosition(androidx.recyclerview.widget.RecyclerView.LayoutManager, int, int);
+    method public boolean onFling(int, int);
+  }
+
+  public class SortedList<T> {
+    ctor public SortedList(Class<T!>, androidx.recyclerview.widget.SortedList.Callback<T!>);
+    ctor public SortedList(Class<T!>, androidx.recyclerview.widget.SortedList.Callback<T!>, int);
+    method public int add(T!);
+    method public void addAll(T![], boolean);
+    method public void addAll(T!...);
+    method public void addAll(java.util.Collection<T!>);
+    method public void beginBatchedUpdates();
+    method public void clear();
+    method public void endBatchedUpdates();
+    method public T! get(int) throws java.lang.IndexOutOfBoundsException;
+    method public int indexOf(T!);
+    method public void recalculatePositionOfItemAt(int);
+    method public boolean remove(T!);
+    method public T! removeItemAt(int);
+    method public void replaceAll(T![], boolean);
+    method public void replaceAll(T!...);
+    method public void replaceAll(java.util.Collection<T!>);
+    method public int size();
+    method public void updateItemAt(int, T!);
+    field public static final int INVALID_POSITION = -1; // 0xffffffff
+  }
+
+  public static class SortedList.BatchedCallback<T2> extends androidx.recyclerview.widget.SortedList.Callback<T2> {
+    ctor public SortedList.BatchedCallback(androidx.recyclerview.widget.SortedList.Callback<T2!>);
+    method public boolean areContentsTheSame(T2!, T2!);
+    method public boolean areItemsTheSame(T2!, T2!);
+    method public int compare(T2!, T2!);
+    method public void dispatchLastEvent();
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public abstract static class SortedList.Callback<T2> implements java.util.Comparator<T2> androidx.recyclerview.widget.ListUpdateCallback {
+    ctor public SortedList.Callback();
+    method public abstract boolean areContentsTheSame(T2!, T2!);
+    method public abstract boolean areItemsTheSame(T2!, T2!);
+    method public abstract int compare(T2!, T2!);
+    method public Object? getChangePayload(T2!, T2!);
+    method public abstract void onChanged(int, int);
+    method public void onChanged(int, int, Object?);
+  }
+
+  public abstract class SortedListAdapterCallback<T2> extends androidx.recyclerview.widget.SortedList.Callback<T2> {
+    ctor public SortedListAdapterCallback(androidx.recyclerview.widget.RecyclerView.Adapter<?>);
+    method public void onChanged(int, int);
+    method public void onInserted(int, int);
+    method public void onMoved(int, int);
+    method public void onRemoved(int, int);
+  }
+
+  public class StaggeredGridLayoutManager extends androidx.recyclerview.widget.RecyclerView.LayoutManager implements androidx.recyclerview.widget.RecyclerView.SmoothScroller.ScrollVectorProvider {
+    ctor public StaggeredGridLayoutManager(android.content.Context!, android.util.AttributeSet!, int, int);
+    ctor public StaggeredGridLayoutManager(int, int);
+    method public android.graphics.PointF! computeScrollVectorForPosition(int);
+    method public int[]! findFirstCompletelyVisibleItemPositions(int[]!);
+    method public int[]! findFirstVisibleItemPositions(int[]!);
+    method public int[]! findLastCompletelyVisibleItemPositions(int[]!);
+    method public int[]! findLastVisibleItemPositions(int[]!);
+    method public androidx.recyclerview.widget.RecyclerView.LayoutParams! generateDefaultLayoutParams();
+    method public int getGapStrategy();
+    method public int getOrientation();
+    method public boolean getReverseLayout();
+    method public int getSpanCount();
+    method public void invalidateSpanAssignments();
+    method public void scrollToPositionWithOffset(int, int);
+    method public void setGapStrategy(int);
+    method public void setOrientation(int);
+    method public void setReverseLayout(boolean);
+    method public void setSpanCount(int);
+    field @Deprecated public static final int GAP_HANDLING_LAZY = 1; // 0x1
+    field public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; // 0x2
+    field public static final int GAP_HANDLING_NONE = 0; // 0x0
+    field public static final int HORIZONTAL = 0; // 0x0
+    field public static final int VERTICAL = 1; // 0x1
+  }
+
+  public static class StaggeredGridLayoutManager.LayoutParams extends androidx.recyclerview.widget.RecyclerView.LayoutParams {
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.content.Context!, android.util.AttributeSet!);
+    ctor public StaggeredGridLayoutManager.LayoutParams(int, int);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.MarginLayoutParams!);
+    ctor public StaggeredGridLayoutManager.LayoutParams(android.view.ViewGroup.LayoutParams!);
+    ctor public StaggeredGridLayoutManager.LayoutParams(androidx.recyclerview.widget.RecyclerView.LayoutParams!);
+    method public final int getSpanIndex();
+    method public boolean isFullSpan();
+    method public void setFullSpan(boolean);
+    field public static final int INVALID_SPAN_ID = -1; // 0xffffffff
+  }
+
+}
+
diff --git a/recyclerview/recyclerview/build.gradle b/recyclerview/recyclerview/build.gradle
index cbc89b6..6a72c31 100644
--- a/recyclerview/recyclerview/build.gradle
+++ b/recyclerview/recyclerview/build.gradle
@@ -11,7 +11,7 @@
     api "androidx.core:core:1.7.0"
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.customview:customview:1.0.0")
-    implementation("androidx.customview:customview-poolingcontainer:1.0.0-alpha01")
+    implementation("androidx.customview:customview-poolingcontainer:1.0.0-beta02")
 
     androidTestImplementation(libs.testExtJunit)
     androidTestImplementation(libs.testCore)
diff --git a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/MessageThreadUtil.java b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/MessageThreadUtil.java
index b56802e3..4286cd6 100644
--- a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/MessageThreadUtil.java
+++ b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/MessageThreadUtil.java
@@ -233,51 +233,60 @@
     static class MessageQueue {
 
         private SyncQueueItem mRoot;
+        private final Object mLock = new Object();
 
-        synchronized SyncQueueItem next() {
-            if (mRoot == null) {
-                return null;
-            }
-            final SyncQueueItem next = mRoot;
-            mRoot = mRoot.next;
-            return next;
-        }
-
-        synchronized void sendMessageAtFrontOfQueue(SyncQueueItem item) {
-            item.next = mRoot;
-            mRoot = item;
-        }
-
-        synchronized void sendMessage(SyncQueueItem item) {
-            if (mRoot == null) {
-                mRoot = item;
-                return;
-            }
-            SyncQueueItem last = mRoot;
-            while (last.next != null) {
-                last = last.next;
-            }
-            last.next = item;
-        }
-
-        synchronized void removeMessages(int what) {
-            while (mRoot != null && mRoot.what == what) {
-                SyncQueueItem item = mRoot;
+        SyncQueueItem next() {
+            synchronized (mLock) {
+                if (mRoot == null) {
+                    return null;
+                }
+                final SyncQueueItem next = mRoot;
                 mRoot = mRoot.next;
-                item.recycle();
+                return next;
             }
-            if (mRoot != null) {
-                SyncQueueItem prev = mRoot;
-                SyncQueueItem item = prev.next;
-                while (item != null) {
-                    SyncQueueItem next = item.next;
-                    if (item.what == what) {
-                        prev.next = next;
-                        item.recycle();
-                    } else {
-                        prev = item;
+        }
+
+        void sendMessageAtFrontOfQueue(SyncQueueItem item) {
+            synchronized (mLock) {
+                item.next = mRoot;
+                mRoot = item;
+            }
+        }
+
+        void sendMessage(SyncQueueItem item) {
+            synchronized (mLock) {
+                if (mRoot == null) {
+                    mRoot = item;
+                    return;
+                }
+                SyncQueueItem last = mRoot;
+                while (last.next != null) {
+                    last = last.next;
+                }
+                last.next = item;
+            }
+        }
+
+        void removeMessages(int what) {
+            synchronized (mLock) {
+                while (mRoot != null && mRoot.what == what) {
+                    SyncQueueItem item = mRoot;
+                    mRoot = mRoot.next;
+                    item.recycle();
+                }
+                if (mRoot != null) {
+                    SyncQueueItem prev = mRoot;
+                    SyncQueueItem item = prev.next;
+                    while (item != null) {
+                        SyncQueueItem next = item.next;
+                        if (item.what == what) {
+                            prev.next = next;
+                            item.recycle();
+                        } else {
+                            prev = item;
+                        }
+                        item = next;
                     }
-                    item = next;
                 }
             }
         }
diff --git a/remotecallback/remotecallback/lint-baseline.xml b/remotecallback/remotecallback/lint-baseline.xml
index ba213831..1f11b4d 100644
--- a/remotecallback/remotecallback/lint-baseline.xml
+++ b/remotecallback/remotecallback/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="WrongConstant"
@@ -13,195 +13,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public T createRemoteCallback(Context context) {"
-        errorLine2="                                  ~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority,"
-        errorLine2="           ~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority,"
-        errorLine2="                                           ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority,"
-        errorLine2="                                                         ~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority,"
-        errorLine2="                                                                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Bundle args, String method) {"
-        errorLine2="            ~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Bundle args, String method) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/AppWidgetProviderWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public T createRemoteCallback(Context context) {"
-        errorLine2="                                  ~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority,"
-        errorLine2="           ~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority,"
-        errorLine2="                                           ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority,"
-        errorLine2="                                                         ~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority,"
-        errorLine2="                                                                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Bundle args, String method) {"
-        errorLine2="            ~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Bundle args, String method) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/BroadcastReceiverWithCallbacks.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority, Bundle args,"
-        errorLine2="    ~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/CallbackBase.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority, Bundle args,"
-        errorLine2="                                    ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/CallbackBase.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority, Bundle args,"
-        errorLine2="                                                  ~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/CallbackBase.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority, Bundle args,"
-        errorLine2="                                                                   ~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/CallbackBase.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    RemoteCallback toRemoteCallback(Class&lt;T> cls, Context context, String authority, Bundle args,"
-        errorLine2="                                                                                     ~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/CallbackBase.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            String method);"
-        errorLine2="            ~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/CallbackBase.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    T createRemoteCallback(Context context);"
-        errorLine2="                           ~~~~~~~">
-        <location
-            file="src/main/java/androidx/remotecallback/CallbackReceiver.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    public String getMethodName() {"
         errorLine2="           ~~~~~~">
         <location
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/InternalXAnnotationValue.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/InternalXAnnotationValue.kt
index 92e456b8..4315bee 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/InternalXAnnotationValue.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/InternalXAnnotationValue.kt
@@ -26,7 +26,7 @@
      * distinguish between `String` and `String[]` you can check `valueType.isArray()`.
      */
     private enum class Kind {
-        BOOLEAN, INT, SHORT, LONG, FLOAT, DOUBLE, BYTE, STRING, ENUM, ANNOTATION, TYPE;
+        BOOLEAN, INT, SHORT, LONG, FLOAT, DOUBLE, BYTE, CHAR, STRING, ENUM, ANNOTATION, TYPE;
         companion object {
             fun of(type: XType): Kind {
                 if (type.isArray()) {
@@ -40,6 +40,7 @@
                     type.typeName == TypeName.FLOAT -> FLOAT
                     type.typeName == TypeName.DOUBLE -> DOUBLE
                     type.typeName == TypeName.BYTE -> BYTE
+                    type.typeName == TypeName.CHAR -> CHAR
                     type.typeName == InternalXAnnotationValue.STRING -> STRING
                     type.typeName.rawTypeName() == CLASS -> TYPE
                     type.typeName.rawTypeName() == KCLASS -> TYPE
@@ -120,6 +121,12 @@
     /** Returns true if the value is a list of [Double] */
     final override fun hasDoubleListValue() = kind == Kind.DOUBLE && hasListValue()
 
+    /** Returns true if the value is an [Char] */
+    final override fun hasCharValue() = kind == Kind.CHAR && !hasListValue()
+
+    /** Returns true if the value is a list of [Char] */
+    final override fun hasCharListValue() = kind == Kind.CHAR && hasListValue()
+
     /** Returns true if the value is an [Byte] */
     final override fun hasByteValue() = kind == Kind.BYTE && !hasListValue()
 
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt
index b0dd98d..c9ca6f5 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/JavaPoetExt.kt
@@ -15,12 +15,15 @@
  */
 package androidx.room.compiler.processing
 
+import java.lang.Character.isISOControl
+import com.squareup.javapoet.AnnotationSpec
 import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.MethodSpec
 import com.squareup.javapoet.ParameterSpec
 import com.squareup.javapoet.ParameterizedTypeName
 import com.squareup.javapoet.TypeName
 import com.squareup.javapoet.TypeSpec
+import javax.lang.model.SourceVersion
 import javax.lang.model.element.Modifier
 import javax.lang.model.type.TypeKind
 import javax.lang.model.type.TypeMirror
@@ -36,6 +39,51 @@
  */
 private val NONE_TYPE_NAME = ClassName.get("androidx.room.compiler.processing.error", "NotAType")
 
+fun XAnnotation.toAnnotationSpec(): AnnotationSpec {
+  val builder = AnnotationSpec.builder(className)
+  annotationValues.forEach { builder.visitAnnotationValue(it) }
+  return builder.build()
+}
+
+private fun AnnotationSpec.Builder.visitAnnotationValue(annotationValue: XAnnotationValue) {
+  val name = annotationValue.name
+  when (val value = annotationValue.value) {
+    is XAnnotation -> addMember(name, "\$L", value.toAnnotationSpec())
+    is XVariableElement -> addMember(name, "\$T.\$L", value.type.typeName, value.name)
+    is XType -> addMember(name, "\$T.class", value.typeName)
+    is List<*> -> value.forEach { if (it is XAnnotationValue) { visitAnnotationValue(it) } }
+    else -> this.addMemberForCommonValue(name, value)
+  }
+}
+
+private fun AnnotationSpec.Builder.addMemberForCommonValue(memberName: String, value: Any?) {
+    requireNotNull(value) { "value == null, constant non-null value expected for $memberName" }
+    require(SourceVersion.isName(memberName)) { "not a valid name: $memberName" }
+    when (value) {
+        is Class<*> -> addMember(memberName, "\$T.class", value)
+        is Enum<*> -> addMember(memberName, "\$T.\$L", value.javaClass, value.name)
+        is String -> addMember(memberName, "\$S", value)
+        is Float -> addMember(memberName, "\$Lf", value)
+        is Char -> addMember(memberName, "'\$L'", characterLiteralWithoutSingleQuotes(value))
+        else -> addMember(memberName, "\$L", value)
+    }
+}
+
+private fun characterLiteralWithoutSingleQuotes(c: Char): String? {
+    // see https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6
+    return when (c) {
+        '\b' -> "\\b" /* \u0008: backspace (BS) */
+        '\t' -> "\\t" /* \u0009: horizontal tab (HT) */
+        '\n' -> "\\n" /* \u000a: linefeed (LF) */
+        '\u000c' -> "\\u000c" /* \u000c: form feed (FF) */
+        '\r' -> "\\r" /* \u000d: carriage return (CR) */
+        '\"' -> "\"" /* \u0022: double quote (") */
+        '\'' -> "\\'" /* \u0027: single quote (') */
+        '\\' -> "\\\\" /* \u005c: backslash (\) */
+        else -> if (isISOControl(c)) String.format("\\u%04x", c.code) else Character.toString(c)
+    }
+}
+
 internal fun TypeMirror.safeTypeName(): TypeName = if (kind == TypeKind.NONE) {
     NONE_TYPE_NAME
 } else {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotationValue.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotationValue.kt
index db883c9..b85213b 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotationValue.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotationValue.kt
@@ -170,6 +170,18 @@
     /** Returns the value as a list of [Byte]. */
     fun asByteList(): List<Byte> = asAnnotationValueList().map { it.asByte() }
 
+    /** Returns true if the value is an [Char] */
+    fun hasCharValue(): Boolean
+
+    /** Returns the value as a [Char]. */
+    fun asChar(): Char = value as Char
+
+    /** Returns true if the value is a list of [Char] */
+    fun hasCharListValue(): Boolean
+
+    /** Returns the value as a list of [Char]. */
+    fun asCharList(): List<Char> = asAnnotationValueList().map { it.asChar() }
+
     /** Returns true if the value is a list. */
     fun hasListValue(): Boolean
 
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
index d5580d0..5269b23 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
@@ -59,6 +59,7 @@
 import com.google.devtools.ksp.symbol.KSClassDeclaration
 import com.google.devtools.ksp.symbol.KSFunctionDeclaration
 import com.google.devtools.ksp.symbol.KSPropertyDeclaration
+import com.google.devtools.ksp.symbol.KSType
 import com.google.devtools.ksp.symbol.KSValueArgument
 import com.google.devtools.ksp.symbol.KSValueParameter
 import javax.annotation.processing.Filer
@@ -191,6 +192,9 @@
     fun XAnnotationValue.toKS(): KSValueArgument = (this as KspAnnotationValue).valueArgument
 
     @JvmStatic
+    fun XType.toKS(): KSType = (this as KspType).ksType
+
+    @JvmStatic
     fun KSClassDeclaration.toXProcessing(env: XProcessingEnv): XTypeElement =
         (env as KspProcessingEnv).wrapClassDeclaration(this)
 
@@ -221,6 +225,10 @@
         )
     }
 
+    @JvmStatic
+    fun KSType.toXProcessing(env: XProcessingEnv): XType =
+        (env as KspProcessingEnv).wrap(this, true)
+
     @Deprecated("This will be removed in a future version of XProcessing.")
     @JvmStatic
     fun XType.getProcessingEnv(): XProcessingEnv {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspJvmTypeResolver.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspJvmTypeResolver.kt
index 39de2f1..489f6fa 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspJvmTypeResolver.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspJvmTypeResolver.kt
@@ -45,13 +45,19 @@
             KSTypeVarianceResolver.WildcardMode.PREFERRED
         }
 
-        // use the jvm type of the declaration so that it also gets its jvm wildcards resolved.
-        val declarationJvmType = (scope.findDeclarationType() as? KspType)?.jvmWildcardTypeOrSelf
-
+        val declarationType = scope.findDeclarationType() as? KspType
         return env.resolveWildcards(
             ksType = delegate.ksType,
             wildcardMode = wildcardMode,
-            declarationType = declarationJvmType?.ksType
+            // See KSTypeVarianceResolver#applyTypeVariance: "If the ksType is from the original
+            // declaration, declarationType should be null".
+            declarationType = if (declarationType == delegate) {
+                null
+            } else {
+                // use the jvm type of the declaration so that it also gets its jvm wildcards
+                // resolved.
+                declarationType?.jvmWildcardTypeOrSelf?.ksType
+            }
         ).let {
             env.wrap(
                 ksType = it,
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt
index f0186ad..b833951 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMethodElement.kt
@@ -93,15 +93,16 @@
      * If this method is declared in the containing class (or in a file), it will be null.
      */
     val declarationMethodType: XMethodType? by lazy {
-        val declaredIn = declaration.closestClassDeclaration()
-        if (declaredIn == null || declaredIn == containing.declaration) {
-            null
-        } else {
-            create(
-                env = env,
-                containing = env.wrapClassDeclaration(declaredIn),
-                declaration = declaration
-            ).executableType
+        declaration.closestClassDeclaration()?.let { declaredIn ->
+            if (declaredIn == containing.declaration) {
+                executableType
+            } else {
+                create(
+                    env = env,
+                    containing = env.wrapClassDeclaration(declaredIn),
+                    declaration = declaration
+                ).executableType
+            }
         }
     }
 
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/TypeInheritanceTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/TypeInheritanceTest.kt
new file mode 100644
index 0000000..9599c6c
--- /dev/null
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/TypeInheritanceTest.kt
@@ -0,0 +1,1020 @@
+/*
+ * 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.room.compiler.processing
+
+import androidx.room.compiler.processing.util.Source
+import androidx.room.compiler.processing.util.XTestInvocation
+import androidx.room.compiler.processing.util.getField
+import androidx.room.compiler.processing.util.getMethodByJvmName
+import androidx.room.compiler.processing.util.getParameter
+import androidx.room.compiler.processing.util.runProcessorTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class TypeInheritanceTest {
+    private fun runTest(
+        fooClass: String,
+        barClass: String,
+        bazClass: String,
+        handler: (XTestInvocation) -> Unit,
+    ) {
+        val src = Source.kotlin(
+            "Foo.kt",
+            """
+            class SubClass : BaseClass<Baz, Bar<Baz>>()
+            open class BaseClass<T1, T2> {
+                val valField : Foo<Bar<Baz>> = TODO()
+                val valFieldT1 : Foo<Bar<T1>> = TODO()
+                val valFieldT2 : Foo<T2> = TODO()
+                var varField : Foo<Bar<Baz>> = TODO()
+                var varFieldT1 : Foo<Bar<T1>> = TODO()
+                var varFieldT2 : Foo<T2> = TODO()
+
+                fun method(param : Foo<Bar<Baz>>, paramT1 : Foo<Bar<T1>>, paramT2 : Foo<T2>) {}
+                fun methodReturn(): Foo<Bar<Baz>> = TODO()
+                fun methodReturnT1(): Foo<Bar<T1>> = TODO()
+                fun methodReturnT2(): Foo<T2> = TODO()
+            }
+            $fooClass
+            $barClass
+            $bazClass
+            """.trimIndent()
+        )
+        runProcessorTest(sources = listOf(src), handler = handler)
+    }
+
+    private fun XTestInvocation.assertFieldType(fieldName: String, expectedTypeName: String) {
+        val sub = processingEnv.requireTypeElement("SubClass")
+        val subField = sub.getField(fieldName).type.typeName.toString()
+        assertThat(subField).isEqualTo(expectedTypeName)
+
+        val base = processingEnv.requireTypeElement("BaseClass")
+        val baseField = base.getField(fieldName).asMemberOf(sub.type).typeName.toString()
+        assertThat(baseField).isEqualTo(expectedTypeName)
+    }
+
+    private fun XTestInvocation.assertParamType(
+        methodName: String,
+        paramName: String,
+        expectedTypeName: String,
+    ) {
+        val sub = processingEnv.requireTypeElement("SubClass")
+        val subMethod = sub.getMethodByJvmName(methodName)
+        val subParam = subMethod.getParameter(paramName)
+        assertThat(subParam.type.typeName.toString()).isEqualTo(expectedTypeName)
+
+        val base = processingEnv.requireTypeElement("BaseClass")
+        val baseMethod = base.getMethodByJvmName(methodName).asMemberOf(sub.type)
+        val paramIndex = subMethod.parameters.indexOf(subParam)
+        assertThat(baseMethod.parameterTypes[paramIndex].typeName.toString())
+            .isEqualTo(expectedTypeName)
+    }
+
+    private fun XTestInvocation.assertReturnType(methodName: String, expectedTypeName: String) {
+        val sub = processingEnv.requireTypeElement("SubClass")
+        val subMethod = sub.getMethodByJvmName(methodName)
+        assertThat(subMethod.returnType.typeName.toString()).isEqualTo(expectedTypeName)
+
+        val base = processingEnv.requireTypeElement("BaseClass")
+        val baseMethod = base.getMethodByJvmName(methodName).asMemberOf(sub.type)
+        assertThat(baseMethod.returnType.typeName.toString()).isEqualTo(expectedTypeName)
+    }
+
+    @Test
+    fun test_Foo_Bar_Baz() {
+        runTest(
+            "class Foo<V>",
+            "class Bar<V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+        }
+    }
+
+    @Test
+    fun test_OpenFoo_Bar_Baz() {
+        runTest(
+            "open class Foo<V>",
+            "class Bar<V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+        }
+    }
+
+    @Test
+    fun test_Foo_OpenBar_Baz() {
+        runTest(
+            "class Foo<V>",
+            "open class Bar<V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+        }
+    }
+
+    @Test
+    fun test_Foo_Bar_OpenBaz() {
+        runTest(
+            "class Foo<V>",
+            "class Bar<V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+        }
+    }
+
+    @Test
+    fun test_OpenFoo_OpenBar_Baz() {
+        runTest(
+            "open class Foo<V>",
+            "open class Bar<V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+        }
+    }
+
+    @Test
+    fun test_OpenFoo_Bar_OpenBaz() {
+        runTest(
+            "open class Foo<V>",
+            "class Bar<V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+        }
+    }
+
+    @Test
+    fun test_Foo_OpenBar_OpenBaz() {
+        runTest(
+            "class Foo<V>",
+            "open class Bar<V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+        }
+    }
+
+    @Test
+    fun test_OpenFoo_OpenBar_OpenBaz() {
+        runTest(
+            "open class Foo<V>",
+            "open class Bar<V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+        }
+    }
+
+    @Test
+    fun test_FooOut_Bar_Baz() {
+        runTest(
+            "class Foo<out V>",
+            "class Bar<V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFooOut_Bar_Baz() {
+        runTest(
+            "open class Foo<out V>",
+            "class Bar<V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_FooOut_OpenBar_Baz() {
+        runTest(
+            "class Foo<out V>",
+            "open class Bar<V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<? extends Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<? extends Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("varField", "Foo<? extends Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_FooOut_Bar_OpenBaz() {
+        runTest(
+            "class Foo<out V>",
+            "class Bar<V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFooOut_OpenBar_Baz() {
+        runTest(
+            "open class Foo<out V>",
+            "open class Bar<V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<? extends Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<? extends Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("varField", "Foo<? extends Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFooOut_Bar_OpenBaz() {
+        runTest(
+            "open class Foo<out V>",
+            "class Bar<V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_FooOut_OpenBar_OpenBaz() {
+        runTest(
+            "class Foo<out V>",
+            "open class Bar<V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<? extends Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<? extends Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("varField", "Foo<? extends Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFooOut_OpenBar_OpenBaz() {
+        runTest(
+            "open class Foo<out V>",
+            "open class Bar<V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<? extends Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<? extends Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("varField", "Foo<? extends Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_Foo_BarOut_Baz() {
+        runTest(
+            "class Foo<V>",
+            "class Bar<out V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFoo_BarOut_Baz() {
+        runTest(
+            "open class Foo<V>",
+            "class Bar<out V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_Foo_OpenBarOut_Baz() {
+        runTest(
+            "class Foo<V>",
+            "open class Bar<out V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_Foo_BarOut_OpenBaz() {
+        runTest(
+            "class Foo<V>",
+            "class Bar<out V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "param", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFoo_OpenBarOut_Baz() {
+        runTest(
+            "open class Foo<V>",
+            "open class Bar<out V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFoo_BarOut_OpenBaz() {
+        runTest(
+            "open class Foo<V>",
+            "class Bar<out V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "param", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_Foo_OpenBarOut_OpenBaz() {
+        runTest(
+            "class Foo<V>",
+            "open class Bar<out V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "param", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFoo_OpenBarOut_OpenBaz() {
+        runTest(
+            "open class Foo<V>",
+            "open class Bar<out V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_FooOut_BarOut_Baz() {
+        runTest(
+            "class Foo<out V>",
+            "class Bar<out V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertParamType(
+                    "method", "paramT1", "Foo<? extends Bar<? extends Baz>>"
+                )
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFooOut_BarOut_Baz() {
+        runTest(
+            "open class Foo<out V>",
+            "class Bar<out V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertParamType(
+                    "method", "paramT1", "Foo<Bar<? extends Baz>>"
+                )
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertParamType(
+                    "method", "paramT1", "Foo<? extends Bar<? extends Baz>>"
+                )
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_FooOut_OpenBarOut_Baz() {
+        runTest(
+            "class Foo<out V>",
+            "open class Bar<out V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+
+            invocation.assertParamType("method", "param", "Foo<? extends Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<? extends Baz>>")
+
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varField", "Foo<? extends Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_FooOut_BarOut_OpenBaz() {
+        runTest(
+            "class Foo<out V>",
+            "class Bar<out V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<? extends Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "param", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varField", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertParamType("method", "param", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertParamType(
+                    "method", "paramT1", "Foo<? extends Bar<? extends Baz>>"
+                )
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFooOut_OpenBarOut_Baz() {
+        runTest(
+            "open class Foo<out V>",
+            "open class Bar<out V>",
+            "class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<? extends Bar<Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varField", "Foo<? extends Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFooOut_BarOut_OpenBaz() {
+        runTest(
+            "open class Foo<out V>",
+            "class Bar<out V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertParamType("method", "param", "Foo<Bar<? extends Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varField", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertParamType("method", "param", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertParamType("method", "paramT1", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_FooOut_OpenBarOut_OpenBaz() {
+        runTest(
+            "class Foo<out V>",
+            "open class Bar<out V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varField", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+
+    @Test
+    fun test_OpenFooOut_OpenBarOut_OpenBaz() {
+        runTest(
+            "open class Foo<out V>",
+            "open class Bar<out V>",
+            "open class Baz",
+        ) { invocation ->
+            invocation.assertFieldType("valField", "Foo<Bar<Baz>>")
+            invocation.assertFieldType("valFieldT1", "Foo<Bar<Baz>>")
+            invocation.assertParamType("method", "param", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertParamType("method", "paramT1", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertParamType("method", "paramT2", "Foo<? extends Bar<? extends Baz>>")
+            invocation.assertReturnType("methodReturn", "Foo<Bar<Baz>>")
+            invocation.assertReturnType("methodReturnT1", "Foo<Bar<Baz>>")
+
+            // TODO(b/237280547): Make KSP type name match KAPT.
+            if (invocation.isKsp) {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varField", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<Bar<Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<Bar<Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<Baz>>")
+            } else {
+                invocation.assertFieldType("valFieldT2", "Foo<Bar<? extends Baz>>")
+                invocation.assertFieldType("varField", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT1", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertFieldType("varFieldT2", "Foo<? extends Bar<? extends Baz>>")
+                invocation.assertReturnType("methodReturnT2", "Foo<Bar<? extends Baz>>")
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
index 8d31100..cd8ddde 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
@@ -16,6 +16,7 @@
 
 package androidx.room.compiler.processing
 
+import androidx.room.compiler.processing.compat.XConverters.toJavac
 import androidx.room.compiler.processing.testcode.JavaAnnotationWithDefaults
 import androidx.room.compiler.processing.testcode.JavaAnnotationWithEnum
 import androidx.room.compiler.processing.testcode.JavaAnnotationWithEnumArray
@@ -37,6 +38,7 @@
 import androidx.room.compiler.processing.util.typeName
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import com.squareup.javapoet.AnnotationSpec
 import com.squareup.javapoet.ClassName
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -119,6 +121,30 @@
     }
 
     @Test
+    fun annotationSpec() {
+        val source = Source.java(
+            "test.MyClass",
+            """
+            package test;
+            import androidx.room.compiler.processing.testcode.TestSuppressWarnings;
+            @TestSuppressWarnings("test")
+            public class MyClass {}
+            """.trimIndent()
+        )
+        runTest(
+            sources = listOf(source),
+        ) { invocation ->
+            val element = invocation.processingEnv.requireTypeElement("test.MyClass")
+            val annotation =
+                element.requireAnnotation(ClassName.get(TestSuppressWarnings::class.java))
+            if (!invocation.isKsp) {
+                assertThat(annotation.toAnnotationSpec())
+                    .isEqualTo(AnnotationSpec.get(annotation.toJavac()))
+            }
+        }
+    }
+
+    @Test
     fun getAnnotationsAnnotatedWith() {
         val source = Source.kotlin(
             "MyClass.kt",
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
index ad0c9ee..78f29d7 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
@@ -476,6 +476,64 @@
     }
 
     @Test
+    fun testCharValue() {
+        runTest(
+            javaSource = Source.java(
+                "MyClass",
+                """
+                @interface MyAnnotation {
+                    char charParam();
+                    char[] charArrayParam();
+                    char[] charVarArgsParam(); // There's no varargs in java so use array
+                }
+                @MyAnnotation(
+                    charParam = '1',
+                    charArrayParam = {'2', '3', '4'},
+                    charVarArgsParam = {'5', '6', '7'}
+                )
+                class MyClass {}
+                """.trimIndent()
+            ) as Source.JavaSource,
+            kotlinSource = Source.kotlin(
+                "MyClass.kt",
+                """
+                annotation class MyAnnotation(
+                    val charParam: Char,
+                    val charArrayParam: CharArray,
+                    vararg val charVarArgsParam: Char,
+                )
+                @MyAnnotation(
+                    charParam = '1',
+                    charArrayParam = ['2', '3', '4'],
+                    charVarArgsParam = ['5', '6', '7'],
+                )
+                class MyClass
+                """.trimIndent()
+            ) as Source.KotlinSource
+        ) { invocation ->
+            val annotation = invocation.processingEnv.requireTypeElement("MyClass")
+                .getAllAnnotations()
+                .single { it.name == "MyAnnotation" }
+
+            val charParam = annotation.getAnnotationValue("charParam")
+            assertThat(charParam.hasCharValue()).isTrue()
+            assertThat(charParam.asChar()).isEqualTo('1')
+
+            val charArrayParam = annotation.getAnnotationValue("charArrayParam")
+            assertThat(charArrayParam.hasCharListValue()).isTrue()
+            assertThat(charArrayParam.asCharList())
+                .containsExactly('2', '3', '4')
+                .inOrder()
+
+            val charVarArgsParam = annotation.getAnnotationValue("charVarArgsParam")
+            assertThat(charVarArgsParam.hasCharListValue()).isTrue()
+            assertThat(charVarArgsParam.asCharList())
+                .containsExactly('5', '6', '7')
+                .inOrder()
+        }
+    }
+
+    @Test
     fun testStringValue() {
         runTest(
             javaSource = Source.java(
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/compat/XConvertersTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/compat/XConvertersTest.kt
index e64872b..fc35d13 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/compat/XConvertersTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/compat/XConvertersTest.kt
@@ -100,22 +100,9 @@
             }
             """.trimIndent()
         )
-        runKaptTest(
+        runProcessorTest(
             sources = listOf(kotlinSrc, javaSrc)
         ) { invocation ->
-            fun TypeMirror.equivalence() = MoreTypes.equivalence().wrap(this)
-
-            val xKotlinClass = invocation.processingEnv.requireTypeElement("KotlinClass.FooImpl")
-            val xJavaClass = invocation.processingEnv.requireTypeElement("JavaClass.FooImpl")
-            val kotlinClass = invocation.getJavacTypeElement("KotlinClass.FooImpl")
-            val javaClass = invocation.getJavacTypeElement("JavaClass.FooImpl")
-
-            // Test toJavac returns an equivalent TypeMirror
-            assertThat(xKotlinClass.type.toJavac().equivalence())
-                .isEqualTo(kotlinClass.asType().equivalence())
-            assertThat(xJavaClass.type.toJavac().equivalence())
-                .isEqualTo(javaClass.asType().equivalence())
-
             // Test toXProcessing returns an equivalent XType
             fun assertEqualTypes(t: XType?, tFromXConverters: XType?) {
                 if (t == tFromXConverters) {
@@ -148,14 +135,48 @@
                         .contains("XType#nullibility cannot be called from this type")
                 }
             }
-            assertEqualTypes(
-                xKotlinClass.type,
-                kotlinClass.asType().toXProcessing(invocation.processingEnv)
-            )
-            assertEqualTypes(
-                xJavaClass.type,
-                javaClass.asType().toXProcessing(invocation.processingEnv)
-            )
+
+            fun TypeMirror.equivalence() = MoreTypes.equivalence().wrap(this)
+
+            val xKotlinClass = invocation.processingEnv.requireTypeElement("KotlinClass.FooImpl")
+            val xJavaClass = invocation.processingEnv.requireTypeElement("JavaClass.FooImpl")
+
+            if (invocation.isKsp) {
+                val kotlinClass = invocation.getKspTypeElement("KotlinClass.FooImpl")
+                val javaClass = invocation.getKspTypeElement("JavaClass.FooImpl")
+
+                assertThat(xKotlinClass.type.toKS())
+                    .isEqualTo(kotlinClass.asType(emptyList()))
+                assertThat(xJavaClass.type.toKS())
+                    .isEqualTo(javaClass.asType(emptyList()))
+
+                assertEqualTypes(
+                    xKotlinClass.type,
+                    kotlinClass.asType(emptyList()).toXProcessing(invocation.processingEnv)
+                )
+                assertEqualTypes(
+                    xJavaClass.type,
+                    javaClass.asType(emptyList()).toXProcessing(invocation.processingEnv)
+                )
+            } else {
+                val kotlinClass = invocation.getJavacTypeElement("KotlinClass.FooImpl")
+                val javaClass = invocation.getJavacTypeElement("JavaClass.FooImpl")
+
+                // Test toJavac returns an equivalent TypeMirror
+                assertThat(xKotlinClass.type.toJavac().equivalence())
+                    .isEqualTo(kotlinClass.asType().equivalence())
+                assertThat(xJavaClass.type.toJavac().equivalence())
+                    .isEqualTo(javaClass.asType().equivalence())
+
+                assertEqualTypes(
+                    xKotlinClass.type,
+                    kotlinClass.asType().toXProcessing(invocation.processingEnv)
+                )
+                assertEqualTypes(
+                    xJavaClass.type,
+                    javaClass.asType().toXProcessing(invocation.processingEnv)
+                )
+            }
         }
     }
 
diff --git a/room/room-guava/lint-baseline.xml b/room/room-guava/lint-baseline.xml
index 8fc617b..a83acbe 100644
--- a/room/room-guava/lint-baseline.xml
+++ b/room/room-guava/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="LambdaLast"
diff --git a/room/room-ktx/src/test/java/androidx/room/MigrationTest.kt b/room/room-ktx/src/test/java/androidx/room/MigrationTest.kt
index fc3cef3..1beb4ca 100644
--- a/room/room-ktx/src/test/java/androidx/room/MigrationTest.kt
+++ b/room/room-ktx/src/test/java/androidx/room/MigrationTest.kt
@@ -53,7 +53,7 @@
         throw UnsupportedOperationException()
     }
 
-    override fun compileStatement(sql: String?): SupportSQLiteStatement {
+    override fun compileStatement(sql: String): SupportSQLiteStatement {
         throw UnsupportedOperationException()
     }
 
@@ -65,12 +65,12 @@
         throw UnsupportedOperationException()
     }
 
-    override fun beginTransactionWithListener(transactionListener: SQLiteTransactionListener?) {
+    override fun beginTransactionWithListener(transactionListener: SQLiteTransactionListener) {
         throw UnsupportedOperationException()
     }
 
     override fun beginTransactionWithListenerNonExclusive(
-        transactionListener: SQLiteTransactionListener?
+        transactionListener: SQLiteTransactionListener
     ) {
         throw UnsupportedOperationException()
     }
@@ -123,48 +123,48 @@
         throw UnsupportedOperationException()
     }
 
-    override fun query(query: String?): Cursor {
+    override fun query(query: String): Cursor {
         throw UnsupportedOperationException()
     }
 
-    override fun query(query: String?, bindArgs: Array<out Any>?): Cursor {
+    override fun query(query: String, bindArgs: Array<out Any>): Cursor {
         throw UnsupportedOperationException()
     }
 
-    override fun query(query: SupportSQLiteQuery?): Cursor {
+    override fun query(query: SupportSQLiteQuery): Cursor {
         throw UnsupportedOperationException()
     }
 
     override fun query(
-        query: SupportSQLiteQuery?,
+        query: SupportSQLiteQuery,
         cancellationSignal: CancellationSignal?
     ): Cursor {
         throw UnsupportedOperationException()
     }
 
-    override fun insert(table: String?, conflictAlgorithm: Int, values: ContentValues?): Long {
+    override fun insert(table: String, conflictAlgorithm: Int, values: ContentValues): Long {
         throw UnsupportedOperationException()
     }
 
-    override fun delete(table: String?, whereClause: String?, whereArgs: Array<out Any>?): Int {
+    override fun delete(table: String, whereClause: String?, whereArgs: Array<out Any>?): Int {
         throw UnsupportedOperationException()
     }
 
     override fun update(
-        table: String?,
+        table: String,
         conflictAlgorithm: Int,
-        values: ContentValues?,
+        values: ContentValues,
         whereClause: String?,
         whereArgs: Array<out Any>?
     ): Int {
         throw UnsupportedOperationException()
     }
 
-    override fun execSQL(sql: String?) {
+    override fun execSQL(sql: String) {
         throw UnsupportedOperationException()
     }
 
-    override fun execSQL(sql: String?, bindArgs: Array<out Any>?) {
+    override fun execSQL(sql: String, bindArgs: Array<out Any>) {
         throw UnsupportedOperationException()
     }
 
@@ -184,7 +184,7 @@
         throw UnsupportedOperationException()
     }
 
-    override fun setLocale(locale: Locale?) {
+    override fun setLocale(locale: Locale) {
         throw UnsupportedOperationException()
     }
 
diff --git a/room/room-runtime/lint-baseline.xml b/room/room-runtime/lint-baseline.xml
index 47c8bc0..d5a2665 100644
--- a/room/room-runtime/lint-baseline.xml
+++ b/room/room-runtime/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="KotlinNullnessAnnotation"
@@ -327,24 +327,6 @@
 
     <issue
         id="NewApi"
-        message="Field requires API level 16 (current min is 14): `WRITE_AHEAD_LOGGING`"
-        errorLine1="                .setJournalMode(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING).build();"
-        errorLine2="                                                         ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/test/java/androidx/room/BuilderTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 16 (current min is 14): `WRITE_AHEAD_LOGGING`"
-        errorLine1="        assertThat(config.journalMode, is(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING));"
-        errorLine2="                                                                   ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/test/java/androidx/room/BuilderTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
         message="Call requires API level 21 (current min is 14): `java.util.Locale#forLanguageTag`"
         errorLine1="        Locale.setDefault(Locale.forLanguageTag(&quot;tr-TR&quot;));"
         errorLine2="                                 ~~~~~~~~~~~~~~">
@@ -379,643 +361,4 @@
             file="src/test/java/androidx/room/SQLiteCopyOpenHelperTest.kt"/>
     </issue>
 
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    @Override"
-        errorLine2="    ^">
-        <location
-            file="src/main/java/androidx/room/SQLiteCopyOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    @Override"
-        errorLine2="    ^">
-        <location
-            file="src/main/java/androidx/room/SQLiteCopyOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    @Override"
-        errorLine2="    ^">
-        <location
-            file="src/main/java/androidx/room/SQLiteCopyOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    @Override"
-        errorLine2="    ^">
-        <location
-            file="src/main/java/androidx/room/TransactionExecutor.java"/>
-    </issue>
-
-    <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="    @SuppressWarnings(&quot;WeakerAccess&quot;)"
-        errorLine2="    ^">
-        <location
-            file="src/main/java/androidx/room/TransactionExecutor.java"/>
-    </issue>
-
-    <issue
-        id="PrivateConstructorForUtilityClass"
-        message="Utility class is missing private constructor"
-        errorLine1="public class Room {"
-        errorLine2="             ~~~~">
-        <location
-            file="src/main/java/androidx/room/Room.java"/>
-    </issue>
-
-    <issue
-        id="UnsafeOptInUsageError"
-        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.room.ExperimentalRoomApi&apos; or &apos;@OptIn(markerClass = androidx.room.ExperimentalRoomApi.class)&apos;"
-        errorLine1="                MultiInstanceInvalidationService.class) : null,"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/DatabaseConfiguration.java"/>
-    </issue>
-
-    <issue
-        id="UnsafeOptInUsageError"
-        message="This declaration is opt-in and its usage should be marked with&#xA;&apos;@androidx.room.ExperimentalRoomApi&apos; or &apos;@OptIn(markerClass = androidx.room.ExperimentalRoomApi.class)&apos;"
-        errorLine1="                    MultiInstanceInvalidationService.class) : null;"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomDatabase.java"/>
-    </issue>
-
-    <issue
-        id="LambdaLast"
-        message="Functional interface parameters (such as parameter 3, &quot;sqliteOpenHelperFactory&quot;, in androidx.room.DatabaseConfiguration.DatabaseConfiguration) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
-        errorLine1="            @Nullable Set&lt;Integer> migrationNotRequiredFrom) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/DatabaseConfiguration.java"/>
-    </issue>
-
-    <issue
-        id="LambdaLast"
-        message="Functional interface parameters (such as parameter 3, &quot;sqliteOpenHelperFactory&quot;, in androidx.room.DatabaseConfiguration.DatabaseConfiguration) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
-        errorLine1="            @Nullable Set&lt;Integer> migrationNotRequiredFrom) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/DatabaseConfiguration.java"/>
-    </issue>
-
-    <issue
-        id="LambdaLast"
-        message="Functional interface parameters (such as parameter 3, &quot;sqliteOpenHelperFactory&quot;, in androidx.room.DatabaseConfiguration.DatabaseConfiguration) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
-        errorLine1="            @Nullable File copyFromFile) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/DatabaseConfiguration.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public EntityDeletionOrUpdateAdapter(RoomDatabase database) {"
-        errorLine2="                                         ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityDeletionOrUpdateAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected abstract String createQuery();"
-        errorLine2="                       ~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityDeletionOrUpdateAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected abstract void bind(SupportSQLiteStatement statement, T entity);"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityDeletionOrUpdateAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final int handleMultiple(Iterable&lt;? extends T> entities) {"
-        errorLine2="                                    ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityDeletionOrUpdateAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final int handleMultiple(T[] entities) {"
-        errorLine2="                                    ~~~">
-        <location
-            file="src/main/java/androidx/room/EntityDeletionOrUpdateAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public EntityInsertionAdapter(RoomDatabase database) {"
-        errorLine2="                                  ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected abstract void bind(SupportSQLiteStatement statement, T entity);"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final void insert(T[] entities) {"
-        errorLine2="                             ~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final void insert(Iterable&lt;? extends T> entities) {"
-        errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final long[] insertAndReturnIdsArray(Collection&lt;? extends T> entities) {"
-        errorLine2="                 ~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final long[] insertAndReturnIdsArray(Collection&lt;? extends T> entities) {"
-        errorLine2="                                                ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final long[] insertAndReturnIdsArray(T[] entities) {"
-        errorLine2="                 ~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final long[] insertAndReturnIdsArray(T[] entities) {"
-        errorLine2="                                                ~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final Long[] insertAndReturnIdsArrayBox(Collection&lt;? extends T> entities) {"
-        errorLine2="                 ~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final Long[] insertAndReturnIdsArrayBox(Collection&lt;? extends T> entities) {"
-        errorLine2="                                                   ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final Long[] insertAndReturnIdsArrayBox(T[] entities) {"
-        errorLine2="                 ~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final Long[] insertAndReturnIdsArrayBox(T[] entities) {"
-        errorLine2="                                                   ~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final List&lt;Long> insertAndReturnIdsList(T[] entities) {"
-        errorLine2="                 ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final List&lt;Long> insertAndReturnIdsList(T[] entities) {"
-        errorLine2="                                                   ~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final List&lt;Long> insertAndReturnIdsList(Collection&lt;? extends T> entities) {"
-        errorLine2="                 ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public final List&lt;Long> insertAndReturnIdsList(Collection&lt;? extends T> entities) {"
-        errorLine2="                                                   ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/EntityInsertionAdapter.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public InvalidationTracker(RoomDatabase database, String... tableNames) {"
-        errorLine2="                               ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public InvalidationTracker(RoomDatabase database, String... tableNames) {"
-        errorLine2="                                                      ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public InvalidationTracker(RoomDatabase database, Map&lt;String, String> shadowTablesMap,"
-        errorLine2="                               ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public InvalidationTracker(RoomDatabase database, Map&lt;String, String> shadowTablesMap,"
-        errorLine2="                                                      ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Map&lt;String, Set&lt;String>> viewTables, String... tableNames) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Map&lt;String, Set&lt;String>> viewTables, String... tableNames) {"
-        errorLine2="                                                 ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void addWeakObserver(Observer observer) {"
-        errorLine2="                                ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void notifyObserversByTableNames(String... tables) {"
-        errorLine2="                                            ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public &lt;T> LiveData&lt;T> createLiveData(String[] tableNames, boolean inTransaction,"
-        errorLine2="               ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public &lt;T> LiveData&lt;T> createLiveData(String[] tableNames, boolean inTransaction,"
-        errorLine2="                                          ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Callable&lt;T> computeFunction) {"
-        errorLine2="            ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="        protected Observer(@NonNull String firstTable, String... rest) {"
-        errorLine2="                                                       ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/InvalidationTracker.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected abstract SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration config);"
-        errorLine2="                                                                ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomDatabase.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public SupportSQLiteStatement compileStatement(@NonNull String sql) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomDatabase.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="        public Builder&lt;T> fallbackToDestructiveMigrationFrom(int... startVersions) {"
-        errorLine2="                                                             ~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomDatabase.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onConfigure(SupportSQLiteDatabase db) {"
-        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(SupportSQLiteDatabase db) {"
-        errorLine2="                         ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onUpgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {"
-        errorLine2="                          ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onDowngrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {"
-        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onOpen(SupportSQLiteDatabase db) {"
-        errorLine2="                       ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="        protected abstract void dropAllTables(SupportSQLiteDatabase database);"
-        errorLine2="                                              ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="        protected abstract void createAllTables(SupportSQLiteDatabase database);"
-        errorLine2="                                                ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="        protected abstract void onOpen(SupportSQLiteDatabase database);"
-        errorLine2="                                       ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="        protected abstract void onCreate(SupportSQLiteDatabase database);"
-        errorLine2="                                         ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="        protected void onPreMigrate(SupportSQLiteDatabase database) {"
-        errorLine2="                                    ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="        protected void onPostMigrate(SupportSQLiteDatabase database) {"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomOpenHelper.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static RoomSQLiteQuery copyFrom(SupportSQLiteQuery supportSQLiteQuery) {"
-        errorLine2="                  ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomSQLiteQuery.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static RoomSQLiteQuery copyFrom(SupportSQLiteQuery supportSQLiteQuery) {"
-        errorLine2="                                           ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomSQLiteQuery.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static RoomSQLiteQuery acquire(String query, int argumentCount) {"
-        errorLine2="                  ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomSQLiteQuery.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static RoomSQLiteQuery acquire(String query, int argumentCount) {"
-        errorLine2="                                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomSQLiteQuery.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public String getSql() {"
-        errorLine2="           ~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomSQLiteQuery.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void bindTo(SupportSQLiteProgram program) {"
-        errorLine2="                       ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomSQLiteQuery.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void bindString(int index, String value) {"
-        errorLine2="                                      ~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomSQLiteQuery.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void bindBlob(int index, byte[] value) {"
-        errorLine2="                                    ~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomSQLiteQuery.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void copyArgumentsFrom(RoomSQLiteQuery other) {"
-        errorLine2="                                  ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/RoomSQLiteQuery.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public SharedSQLiteStatement(RoomDatabase database) {"
-        errorLine2="                                 ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/SharedSQLiteStatement.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected abstract String createQuery();"
-        errorLine2="                       ~~~~~~">
-        <location
-            file="src/main/java/androidx/room/SharedSQLiteStatement.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public SupportSQLiteStatement acquire() {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/SharedSQLiteStatement.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void release(SupportSQLiteStatement statement) {"
-        errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/room/SharedSQLiteStatement.java"/>
-    </issue>
-
 </issues>
diff --git a/room/room-runtime/src/main/java/androidx/room/AutoClosingRoomOpenHelper.kt b/room/room-runtime/src/main/java/androidx/room/AutoClosingRoomOpenHelper.kt
index ad51290..d32cf1d 100644
--- a/room/room-runtime/src/main/java/androidx/room/AutoClosingRoomOpenHelper.kt
+++ b/room/room-runtime/src/main/java/androidx/room/AutoClosingRoomOpenHelper.kt
@@ -265,7 +265,7 @@
         @RequiresApi(api = Build.VERSION_CODES.N)
         override fun query(
             query: SupportSQLiteQuery,
-            cancellationSignal: CancellationSignal
+            cancellationSignal: CancellationSignal?
         ): Cursor {
             val result = try {
                 autoCloser.incrementCountAndEnsureDbIsOpen().query(query, cancellationSignal)
@@ -286,7 +286,7 @@
             }
         }
 
-        override fun delete(table: String, whereClause: String, whereArgs: Array<Any>): Int {
+        override fun delete(table: String, whereClause: String?, whereArgs: Array<Any>?): Int {
             return autoCloser.executeRefCountingFunction { db: SupportSQLiteDatabase ->
                 db.delete(
                     table,
@@ -300,8 +300,8 @@
             table: String,
             conflictAlgorithm: Int,
             values: ContentValues,
-            whereClause: String,
-            whereArgs: Array<Any>
+            whereClause: String?,
+            whereArgs: Array<Any>?
         ): Int {
             return autoCloser.executeRefCountingFunction { db: SupportSQLiteDatabase ->
                 db.update(
@@ -348,7 +348,7 @@
             }
         }
 
-        override fun getPath(): String {
+        override fun getPath(): String? {
             return autoCloser.executeRefCountingFunction { obj: SupportSQLiteDatabase ->
                 obj.path
             }
@@ -402,7 +402,7 @@
             }
         }
 
-        override fun getAttachedDbs(): List<Pair<String, String>> {
+        override fun getAttachedDbs(): List<Pair<String, String>>? {
             return autoCloser.executeRefCountingFunction {
                     obj: SupportSQLiteDatabase -> obj.attachedDbs
             }
@@ -552,7 +552,7 @@
             }
         }
 
-        override fun simpleQueryForString(): String {
+        override fun simpleQueryForString(): String? {
             return executeSqliteStatementWithRefCount { obj: SupportSQLiteStatement ->
                 obj.simpleQueryForString()
             }
diff --git a/room/room-runtime/src/main/java/androidx/room/QueryInterceptorDatabase.kt b/room/room-runtime/src/main/java/androidx/room/QueryInterceptorDatabase.kt
index f46fe60..1ae68ea3 100644
--- a/room/room-runtime/src/main/java/androidx/room/QueryInterceptorDatabase.kt
+++ b/room/room-runtime/src/main/java/androidx/room/QueryInterceptorDatabase.kt
@@ -19,7 +19,6 @@
 import android.database.Cursor
 import android.database.sqlite.SQLiteTransactionListener
 import android.os.CancellationSignal
-import androidx.annotation.NonNull
 
 import androidx.sqlite.db.SupportSQLiteDatabase
 import androidx.sqlite.db.SupportSQLiteQuery
@@ -109,10 +108,9 @@
         return delegate.query(query)
     }
 
-    @NonNull
     override fun query(
-        @NonNull query: SupportSQLiteQuery,
-        @NonNull cancellationSignal: CancellationSignal?
+        query: SupportSQLiteQuery,
+        cancellationSignal: CancellationSignal?
     ): Cursor {
         val queryInterceptorProgram = QueryInterceptorProgram()
         query.bindTo(queryInterceptorProgram)
@@ -138,7 +136,7 @@
     // Suppress warning about `SQL` in execSQL not being camel case. This is an override function
     // and it can't be renamed.
     @Suppress("AcronymName")
-    override fun execSQL(sql: String, vararg bindArgs: Any) {
+    override fun execSQL(sql: String, bindArgs: Array<Any>) {
         val inputArguments = mutableListOf<Any>()
         inputArguments.addAll(listOf(bindArgs))
         queryCallbackExecutor.execute {
diff --git a/room/room-runtime/src/main/java/androidx/room/QueryInterceptorProgram.kt b/room/room-runtime/src/main/java/androidx/room/QueryInterceptorProgram.kt
index 281df01..49aea34 100644
--- a/room/room-runtime/src/main/java/androidx/room/QueryInterceptorProgram.kt
+++ b/room/room-runtime/src/main/java/androidx/room/QueryInterceptorProgram.kt
@@ -36,11 +36,11 @@
         saveArgsToCache(index, value)
     }
 
-    override fun bindString(index: Int, value: String?) {
+    override fun bindString(index: Int, value: String) {
         saveArgsToCache(index, value)
     }
 
-    override fun bindBlob(index: Int, value: ByteArray?) {
+    override fun bindBlob(index: Int, value: ByteArray) {
         saveArgsToCache(index, value)
     }
 
diff --git a/room/room-runtime/src/main/java/androidx/room/QueryInterceptorStatement.kt b/room/room-runtime/src/main/java/androidx/room/QueryInterceptorStatement.kt
index a182885..2ec9508 100644
--- a/room/room-runtime/src/main/java/androidx/room/QueryInterceptorStatement.kt
+++ b/room/room-runtime/src/main/java/androidx/room/QueryInterceptorStatement.kt
@@ -60,7 +60,7 @@
         return delegate.simpleQueryForLong()
     }
 
-    override fun simpleQueryForString(): String {
+    override fun simpleQueryForString(): String? {
         queryCallbackExecutor.execute {
             queryCallback.onQuery(sqlStatement, bindArgsCache)
         }
@@ -82,12 +82,12 @@
         delegate.bindDouble(index, value)
     }
 
-    override fun bindString(index: Int, value: String?) {
+    override fun bindString(index: Int, value: String) {
         saveArgsToCache(index, value)
         delegate.bindString(index, value)
     }
 
-    override fun bindBlob(index: Int, value: ByteArray?) {
+    override fun bindBlob(index: Int, value: ByteArray) {
         saveArgsToCache(index, value)
         delegate.bindBlob(index, value)
     }
diff --git a/room/room-runtime/src/main/java/androidx/room/RoomSQLiteQuery.kt b/room/room-runtime/src/main/java/androidx/room/RoomSQLiteQuery.kt
index 8f9ed4d..4c0ee9b 100644
--- a/room/room-runtime/src/main/java/androidx/room/RoomSQLiteQuery.kt
+++ b/room/room-runtime/src/main/java/androidx/room/RoomSQLiteQuery.kt
@@ -104,8 +104,8 @@
                 NULL -> program.bindNull(index)
                 LONG -> program.bindLong(index, longBindings[index])
                 DOUBLE -> program.bindDouble(index, doubleBindings[index])
-                STRING -> program.bindString(index, stringBindings[index])
-                BLOB -> program.bindBlob(index, blobBindings[index])
+                STRING -> program.bindString(index, requireNotNull(stringBindings[index]))
+                BLOB -> program.bindBlob(index, requireNotNull(blobBindings[index]))
             }
         }
     }
diff --git a/room/room-rxjava2/lint-baseline.xml b/room/room-rxjava2/lint-baseline.xml
index d16eebd..beacd64 100644
--- a/room/room-rxjava2/lint-baseline.xml
+++ b/room/room-rxjava2/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="PrivateConstructorForUtilityClass"
diff --git a/room/room-testing/lint-baseline.xml b/room/room-testing/lint-baseline.xml
index 6bd249e..57b3def 100644
--- a/room/room-testing/lint-baseline.xml
+++ b/room/room-testing/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
diff --git a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/DetailsDescriptionPresenter.java b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/DetailsDescriptionPresenter.java
index 932f187..a15c130 100644
--- a/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/DetailsDescriptionPresenter.java
+++ b/samples/SupportLeanbackDemos/src/main/java/com/example/android/leanback/DetailsDescriptionPresenter.java
@@ -13,12 +13,13 @@
  */
 package com.example.android.leanback;
 
+import androidx.annotation.NonNull;
 import androidx.leanback.widget.AbstractDetailsDescriptionPresenter;
 
 public class DetailsDescriptionPresenter extends AbstractDetailsDescriptionPresenter {
 
     @Override
-    protected void onBindDescription(ViewHolder vh, Object item) {
+    protected void onBindDescription(@NonNull ViewHolder vh, @NonNull Object item) {
         vh.getTitle().setText(item.toString());
         vh.getSubtitle().setText("2013 - 2014   Drama   TV-14");
         vh.getBody().setText("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
diff --git a/security/security-crypto/lint-baseline.xml b/security/security-crypto/lint-baseline.xml
index 95f8861..7d4fade 100644
--- a/security/security-crypto/lint-baseline.xml
+++ b/security/security-crypto/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="BanSynchronizedMethods"
diff --git a/security/security-identity-credential/lint-baseline.xml b/security/security-identity-credential/lint-baseline.xml
index be1c80c..1fc8cd4 100644
--- a/security/security-identity-credential/lint-baseline.xml
+++ b/security/security-identity-credential/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="WrongConstant"
diff --git a/settings.gradle b/settings.gradle
index bd19f12..66e19e6 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,4 +1,6 @@
 import groovy.transform.Field
+import androidx.build.gradle.gcpbuildcache.GcpBuildCache
+import androidx.build.gradle.gcpbuildcache.GcpBuildCacheServiceFactory
 
 pluginManagement {
     repositories {
@@ -70,6 +72,7 @@
 apply(plugin: "com.gradle.common-custom-user-data-gradle-plugin")
 apply(plugin: "androidx.build.gradle.gcpbuildcache")
 
+def BUILD_NUMBER = System.getenv("BUILD_NUMBER")
 gradleEnterprise {
     server = "https://ge.androidx.dev"
 
@@ -81,10 +84,9 @@
             hostname { host -> "unset" }
             ipAddresses { addresses -> addresses.collect { address -> "0.0.0.0"} }
         }
-        def buildNumber = System.getenv("BUILD_NUMBER")
-        if (buildNumber != null) {
-            value("BUILD_NUMBER", buildNumber)
-            link("ci.android.com build", "https://ci.android.com/builds/branches/aosp-androidx-main/grid?head=$buildNumber&tail=$buildNumber")
+        if (BUILD_NUMBER != null) {
+            value("BUILD_NUMBER", BUILD_NUMBER)
+            link("ci.android.com build", "https://ci.android.com/builds/branches/aosp-androidx-main/grid?head=$BUILD_NUMBER&tail=$BUILD_NUMBER")
         }
         value("androidx.compose.multiplatformEnabled", isMultiplatformEnabled().toString())
         value("androidx.projects", getRequestedProjectSubsetName() ?: "Unset")
@@ -95,6 +97,37 @@
     }
 }
 
+def cacheSetting = System.getenv("USE_ANDROIDX_REMOTE_BUILD_CACHE")
+switch (cacheSetting) {
+    case ["true", "uplink"]: // legacy build cache
+        logger.warn("\u001B[31m\nYou are using legacy USE_ANDROIDX_REMOTE_BUILD_CACHE=$cacheSetting " +
+                "type, this cache has been turned down, so you are *not* using a remote cache. " +
+                "Please move to the new cache using http://go/androidx-dev#remote-build-cache\u001B[0m\n")
+        break
+    case "gcp":
+        buildCache {
+            registerBuildCacheService(GcpBuildCache, GcpBuildCacheServiceFactory)
+        }
+        settings.buildCache {
+            remote(GcpBuildCache) {
+                projectId = "androidx-ge"
+                bucketName = "androidx-gradle-remote-cache"
+                push = (BUILD_NUMBER != null && !BUILD_NUMBER.startsWith("P"))
+            }
+        }
+        break
+    case "false":
+        break
+    default:
+        def uplinkLinux = new File("/usr/bin/uplink-helper")
+        def uplinkMac = new File("/usr/local/bin/uplink-helper")
+        if (uplinkLinux.exists() || uplinkMac.exists()) {
+            logger.warn("\u001B[31m\nIt looks like you are a Googler running without remote build "
+                    + "cache. Enable it for faster builds, see " +
+                    "http://go/androidx-dev#remote-build-cache\u001B[0m\n")
+        }
+}
+
 rootProject.name = "androidx"
 
 dependencyResolutionManagement {
@@ -610,6 +643,7 @@
 includeProject(":glance:glance-wear-tiles", [BuildType.MAIN, BuildType.GLANCE])
 includeProject(":gridlayout:gridlayout", [BuildType.MAIN])
 includeProject(":health:health-connect-client", [BuildType.MAIN])
+includeProject(":health:health-connect-client-proto", [BuildType.MAIN])
 includeProject(":health:health-services-client", [BuildType.MAIN])
 includeProject(":heifwriter:heifwriter", [BuildType.MAIN])
 includeProject(":hilt:hilt-common", [BuildType.MAIN])
@@ -785,6 +819,7 @@
 includeProject(":startup:startup-runtime-lint", [BuildType.MAIN])
 includeProject(":swiperefreshlayout:swiperefreshlayout", [BuildType.MAIN])
 includeProject(":test:ext:junit-gtest", [BuildType.MAIN])
+includeProject(":test:integration-tests:junit-gtest-test", [BuildType.MAIN])
 includeProject(":test:screenshot:screenshot")
 includeProject(":test:screenshot:screenshot-proto", "test/screenshot/screenshot/proto")
 includeProject(":test:uiautomator:uiautomator", [BuildType.MAIN])
@@ -909,6 +944,7 @@
 /////////////////////////////
 
 includeProject(":internal-testutils-common", "testutils/testutils-common", [BuildType.MAIN, BuildType.COMPOSE])
+includeProject(":internal-testutils-datastore", "testutils/testutils-datastore", [BuildType.MAIN])
 includeProject(":internal-testutils-runtime", "testutils/testutils-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.MEDIA, BuildType.WEAR])
 includeProject(":internal-testutils-appcompat", "testutils/testutils-appcompat", [BuildType.MAIN])
 includeProject(":internal-testutils-espresso", "testutils/testutils-espresso", [BuildType.MAIN, BuildType.COMPOSE])
@@ -971,11 +1007,3 @@
 includeProject(":placeholder-tests")
 
 includeProject(":fakeannotations")
-
-/////////////////////////////
-//
-// Remote build cache set up
-//
-/////////////////////////////
-
-apply from: new File("buildSrc/remoteBuildCache.gradle")
diff --git a/sharetarget/sharetarget/lint-baseline.xml b/sharetarget/sharetarget/lint-baseline.xml
index bee2da3..fa922df 100644
--- a/sharetarget/sharetarget/lint-baseline.xml
+++ b/sharetarget/sharetarget/lint-baseline.xml
@@ -1,365 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Class requires API level 19 (current min is 14): `ShortcutInfoCompatSaverImpl`"
-        errorLine1="        mShortcutSaver = mock(ShortcutInfoCompatSaverImpl.class);"
-        errorLine2="                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ChooserTargetServiceCompatTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcutIcon`"
-        errorLine1="        when(mShortcutSaver.getShortcutIcon(any())).thenReturn(mTestIcon);"
-        errorLine2="                            ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ChooserTargetServiceCompatTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `createExecutorService`"
-        errorLine1="        mCacheUpdateService = ShortcutInfoCompatSaverImpl.createExecutorService();"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `createExecutorService`"
-        errorLine1="        mDiskIoService = ShortcutInfoCompatSaverImpl.createExecutorService();"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `ShortcutInfoCompatSaverImpl`"
-        errorLine1="        mShortcutInfoSaver = new ShortcutInfoCompatSaverImpl(mContext, mCacheUpdateService,"
-        errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `removeAllShortcuts`"
-        errorLine1="        catchAsyncExceptions(mShortcutInfoSaver.removeAllShortcuts());"
-        errorLine2="                                                ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `removeAllShortcuts`"
-        errorLine1="            mShortcutInfoSaver.removeAllShortcuts().get();"
-        errorLine2="                               ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getInstance`"
-        errorLine1="                ShortcutInfoCompatSaverImpl.getInstance(mContext);"
-        errorLine2="                                            ~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getInstance`"
-        errorLine1="        assertEquals(saver, ShortcutInfoCompatSaverImpl.getInstance(mContext));"
-        errorLine2="                                                        ~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        List&lt;ShortcutInfoCompat> shortcuts = mShortcutInfoSaver.getShortcuts();"
-        errorLine2="                                                                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `addShortcuts`"
-        errorLine1="        catchAsyncExceptions(mShortcutInfoSaver.addShortcuts(mTestShortcuts));"
-        errorLine2="                                                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        assertShortcutsListEquals(testShortcutsWithCategories(), mShortcutInfoSaver.getShortcuts());"
-        errorLine2="                                                                                    ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `addShortcuts`"
-        errorLine1="        ListenableFuture&lt;?> future = mShortcutInfoSaver.addShortcuts(mTestShortcuts);"
-        errorLine2="                                                        ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        assertShortcutsListEquals(testShortcutsWithCategories(), mShortcutInfoSaver.getShortcuts());"
-        errorLine2="                                                                                    ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `addShortcuts`"
-        errorLine1="        catchAsyncExceptions(mShortcutInfoSaver.addShortcuts(firstBatch));"
-        errorLine2="                                                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `addShortcuts`"
-        errorLine1="        ListenableFuture&lt;Void> future = mShortcutInfoSaver.addShortcuts(secondBatch);"
-        errorLine2="                                                           ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        assertShortcutsListEquals(allShortcuts, mShortcutInfoSaver.getShortcuts());"
-        errorLine2="                                                                   ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        assertShortcutsListEquals(allShortcuts, mShortcutInfoSaver.getShortcuts());"
-        errorLine2="                                                                   ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `addShortcuts`"
-        errorLine1="        catchAsyncExceptions(mShortcutInfoSaver.addShortcuts(mTestShortcuts));"
-        errorLine2="                                                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `removeShortcuts`"
-        errorLine1="        ListenableFuture&lt;?> future = mShortcutInfoSaver.removeShortcuts(removeIds);"
-        errorLine2="                                                        ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        assertShortcutsListEquals(testShortcutsWithCategories(), mShortcutInfoSaver.getShortcuts());"
-        errorLine2="                                                                                    ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        assertShortcutsListEquals(testShortcutsWithCategories(), mShortcutInfoSaver.getShortcuts());"
-        errorLine2="                                                                                    ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `addShortcuts`"
-        errorLine1="        catchAsyncExceptions(mShortcutInfoSaver.addShortcuts(mTestShortcuts));"
-        errorLine2="                                                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        assertShortcutsListEquals(testShortcutsWithCategories(), mShortcutInfoSaver.getShortcuts());"
-        errorLine2="                                                                                    ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `removeAllShortcuts`"
-        errorLine1="        ListenableFuture&lt;?> future = mShortcutInfoSaver.removeAllShortcuts();"
-        errorLine2="                                                        ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        assertTrue(mShortcutInfoSaver.getShortcuts().isEmpty());"
-        errorLine2="                                      ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        assertTrue(mShortcutInfoSaver.getShortcuts().isEmpty());"
-        errorLine2="                                      ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `addShortcuts`"
-        errorLine1="        ListenableFuture&lt;?> future = mShortcutInfoSaver.addShortcuts(mTestShortcuts);"
-        errorLine2="                                                        ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        List&lt;ShortcutInfoCompat> shortcuts = mShortcutInfoSaver.getShortcuts();"
-        errorLine2="                                                                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `addShortcuts`"
-        errorLine1="        catchAsyncExceptions(mShortcutInfoSaver.addShortcuts(mTestShortcuts));"
-        errorLine2="                                                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        List&lt;ShortcutInfoCompat> shortcuts = mShortcutInfoSaver.getShortcuts();"
-        errorLine2="                                                                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcutIcon`"
-        errorLine1="            verifyCorrectIconLoaded(item.getId(), mShortcutInfoSaver.getShortcutIcon(item.getId()));"
-        errorLine2="                                                                     ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `addShortcuts`"
-        errorLine1="        ListenableFuture&lt;?> future = mShortcutInfoSaver.addShortcuts(mTestShortcuts);"
-        errorLine2="                                                        ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcuts`"
-        errorLine1="        List&lt;ShortcutInfoCompat> shortcuts = mShortcutInfoSaver.getShortcuts();"
-        errorLine2="                                                                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcutIcon`"
-        errorLine1="            verifyCorrectIconLoaded(item.getId(), mShortcutInfoSaver.getShortcutIcon(item.getId()));"
-        errorLine2="                                                                     ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `addShortcuts`"
-        errorLine1="        catchAsyncExceptions(mShortcutInfoSaver.addShortcuts(mTestShortcuts));"
-        errorLine2="                                                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `getShortcutIcon`"
-        errorLine1="        assertNull(mShortcutInfoSaver.getShortcutIcon(&quot;unknown-id&quot;));"
-        errorLine2="                                      ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `createExecutorService`"
-        errorLine1="        mCacheUpdateService = ShortcutInfoCompatSaverImpl.createExecutorService();"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `createExecutorService`"
-        errorLine1="        mDiskIoService = ShortcutInfoCompatSaverImpl.createExecutorService();"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `ShortcutInfoCompatSaverImpl`"
-        errorLine1="        mShortcutInfoSaver = new ShortcutInfoCompatSaverImpl(mContext, mCacheUpdateService,"
-        errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/sharetarget/ShortcutInfoCompatSaverTest.java"/>
-    </issue>
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
diff --git a/slice/slice-builders/api/current.txt b/slice/slice-builders/api/current.txt
index c8118ae..2eb8c22 100644
--- a/slice/slice-builders/api/current.txt
+++ b/slice/slice-builders/api/current.txt
@@ -178,7 +178,7 @@
     method public boolean isDefaultToggle();
     method public boolean isToggle();
     method public androidx.slice.builders.SliceAction setChecked(boolean);
-    method public androidx.slice.builders.SliceAction setContentDescription(CharSequence);
+    method public androidx.slice.core.SliceAction setContentDescription(CharSequence);
     method public androidx.slice.builders.SliceAction setKey(String);
     method public androidx.slice.builders.SliceAction setPriority(@IntRange(from=0) int);
   }
diff --git a/slice/slice-builders/api/public_plus_experimental_current.txt b/slice/slice-builders/api/public_plus_experimental_current.txt
index c8118ae..2eb8c22 100644
--- a/slice/slice-builders/api/public_plus_experimental_current.txt
+++ b/slice/slice-builders/api/public_plus_experimental_current.txt
@@ -178,7 +178,7 @@
     method public boolean isDefaultToggle();
     method public boolean isToggle();
     method public androidx.slice.builders.SliceAction setChecked(boolean);
-    method public androidx.slice.builders.SliceAction setContentDescription(CharSequence);
+    method public androidx.slice.core.SliceAction setContentDescription(CharSequence);
     method public androidx.slice.builders.SliceAction setKey(String);
     method public androidx.slice.builders.SliceAction setPriority(@IntRange(from=0) int);
   }
diff --git a/slice/slice-builders/api/restricted_current.txt b/slice/slice-builders/api/restricted_current.txt
index fb8a38d..ee28dd3 100644
--- a/slice/slice-builders/api/restricted_current.txt
+++ b/slice/slice-builders/api/restricted_current.txt
@@ -198,7 +198,7 @@
     method public boolean isDefaultToggle();
     method public boolean isToggle();
     method public androidx.slice.builders.SliceAction setChecked(boolean);
-    method public androidx.slice.builders.SliceAction setContentDescription(CharSequence);
+    method public androidx.slice.core.SliceAction setContentDescription(CharSequence);
     method public androidx.slice.builders.SliceAction setKey(String);
     method public androidx.slice.builders.SliceAction setPriority(@IntRange(from=0) int);
   }
diff --git a/slice/slice-builders/lint-baseline.xml b/slice/slice-builders/lint-baseline.xml
index 5ee377f..251ab76 100644
--- a/slice/slice-builders/lint-baseline.xml
+++ b/slice/slice-builders/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="WrongConstant"
diff --git a/slice/slice-builders/src/main/java/androidx/slice/builders/SliceAction.java b/slice/slice-builders/src/main/java/androidx/slice/builders/SliceAction.java
index 694e391..0109be7 100644
--- a/slice/slice-builders/src/main/java/androidx/slice/builders/SliceAction.java
+++ b/slice/slice-builders/src/main/java/androidx/slice/builders/SliceAction.java
@@ -329,10 +329,12 @@
 
     /**
      * @param description the content description for this action.
+     * @return
      */
     @NonNull
     @Override
-    public SliceAction setContentDescription(@NonNull CharSequence description) {
+    public androidx.slice.core.SliceAction setContentDescription(
+            @NonNull CharSequence description) {
         mSliceAction.setContentDescription(description);
         return this;
     }
diff --git a/slice/slice-core/api/current.txt b/slice/slice-core/api/current.txt
index 8bd0958..3e0e604 100644
--- a/slice/slice-core/api/current.txt
+++ b/slice/slice-core/api/current.txt
@@ -9,24 +9,24 @@
   }
 
   @RequiresApi(28) public class SliceConvert {
-    method public static android.app.slice.Slice! unwrap(androidx.slice.Slice!);
-    method public static androidx.slice.Slice! wrap(android.app.slice.Slice!, android.content.Context!);
+    method public static android.app.slice.Slice? unwrap(androidx.slice.Slice?);
+    method public static androidx.slice.Slice? wrap(android.app.slice.Slice?, android.content.Context);
   }
 
   @RequiresApi(19) public final class SliceItem implements androidx.versionedparcelable.VersionedParcelable {
     method public static android.text.ParcelableSpan createSensitiveSpan();
     method public void fireAction(android.content.Context?, android.content.Intent?) throws android.app.PendingIntent.CanceledException;
-    method public android.app.PendingIntent! getAction();
-    method public String! getFormat();
+    method public android.app.PendingIntent? getAction();
+    method public String getFormat();
     method public java.util.List<java.lang.String!> getHints();
-    method public androidx.core.graphics.drawable.IconCompat! getIcon();
+    method public androidx.core.graphics.drawable.IconCompat? getIcon();
     method public int getInt();
     method public long getLong();
     method public CharSequence? getRedactedText();
-    method public androidx.slice.Slice! getSlice();
-    method public String! getSubType();
-    method public CharSequence! getText();
-    method public boolean hasHint(String!);
+    method public androidx.slice.Slice? getSlice();
+    method public String? getSubType();
+    method public CharSequence? getText();
+    method public boolean hasHint(String);
     method public void onPostParceling();
     method public void onPreParceling(boolean);
   }
@@ -78,10 +78,10 @@
     method public boolean isChecked();
     method public boolean isDefaultToggle();
     method public boolean isToggle();
-    method public androidx.slice.core.SliceAction! setChecked(boolean);
-    method public androidx.slice.core.SliceAction? setContentDescription(CharSequence);
+    method public androidx.slice.core.SliceAction setChecked(boolean);
+    method public androidx.slice.core.SliceAction setContentDescription(CharSequence);
     method public androidx.slice.core.SliceAction setKey(String);
-    method public androidx.slice.core.SliceAction! setPriority(@IntRange(from=0) int);
+    method public androidx.slice.core.SliceAction setPriority(@IntRange(from=0) int);
   }
 
 }
diff --git a/slice/slice-core/api/public_plus_experimental_current.txt b/slice/slice-core/api/public_plus_experimental_current.txt
index 8bd0958..3e0e604 100644
--- a/slice/slice-core/api/public_plus_experimental_current.txt
+++ b/slice/slice-core/api/public_plus_experimental_current.txt
@@ -9,24 +9,24 @@
   }
 
   @RequiresApi(28) public class SliceConvert {
-    method public static android.app.slice.Slice! unwrap(androidx.slice.Slice!);
-    method public static androidx.slice.Slice! wrap(android.app.slice.Slice!, android.content.Context!);
+    method public static android.app.slice.Slice? unwrap(androidx.slice.Slice?);
+    method public static androidx.slice.Slice? wrap(android.app.slice.Slice?, android.content.Context);
   }
 
   @RequiresApi(19) public final class SliceItem implements androidx.versionedparcelable.VersionedParcelable {
     method public static android.text.ParcelableSpan createSensitiveSpan();
     method public void fireAction(android.content.Context?, android.content.Intent?) throws android.app.PendingIntent.CanceledException;
-    method public android.app.PendingIntent! getAction();
-    method public String! getFormat();
+    method public android.app.PendingIntent? getAction();
+    method public String getFormat();
     method public java.util.List<java.lang.String!> getHints();
-    method public androidx.core.graphics.drawable.IconCompat! getIcon();
+    method public androidx.core.graphics.drawable.IconCompat? getIcon();
     method public int getInt();
     method public long getLong();
     method public CharSequence? getRedactedText();
-    method public androidx.slice.Slice! getSlice();
-    method public String! getSubType();
-    method public CharSequence! getText();
-    method public boolean hasHint(String!);
+    method public androidx.slice.Slice? getSlice();
+    method public String? getSubType();
+    method public CharSequence? getText();
+    method public boolean hasHint(String);
     method public void onPostParceling();
     method public void onPreParceling(boolean);
   }
@@ -78,10 +78,10 @@
     method public boolean isChecked();
     method public boolean isDefaultToggle();
     method public boolean isToggle();
-    method public androidx.slice.core.SliceAction! setChecked(boolean);
-    method public androidx.slice.core.SliceAction? setContentDescription(CharSequence);
+    method public androidx.slice.core.SliceAction setChecked(boolean);
+    method public androidx.slice.core.SliceAction setContentDescription(CharSequence);
     method public androidx.slice.core.SliceAction setKey(String);
-    method public androidx.slice.core.SliceAction! setPriority(@IntRange(from=0) int);
+    method public androidx.slice.core.SliceAction setPriority(@IntRange(from=0) int);
   }
 
 }
diff --git a/slice/slice-core/api/restricted_current.txt b/slice/slice-core/api/restricted_current.txt
index e0bbc2f..def0c1d 100644
--- a/slice/slice-core/api/restricted_current.txt
+++ b/slice/slice-core/api/restricted_current.txt
@@ -47,38 +47,38 @@
   }
 
   @RequiresApi(28) public class SliceConvert {
-    method public static android.app.slice.Slice! unwrap(androidx.slice.Slice!);
-    method public static androidx.slice.Slice! wrap(android.app.slice.Slice!, android.content.Context!);
+    method public static android.app.slice.Slice? unwrap(androidx.slice.Slice?);
+    method public static androidx.slice.Slice? wrap(android.app.slice.Slice?, android.content.Context);
   }
 
   @RequiresApi(19) @androidx.versionedparcelable.VersionedParcelize(allowSerialization=true, ignoreParcelables=true, isCustom=true) public final class SliceItem extends androidx.versionedparcelable.CustomVersionedParcelable {
-    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public SliceItem(Object!, String!, String!, String![]!);
-    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public SliceItem(Object!, String!, String!, java.util.List<java.lang.String!>!);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public SliceItem(Object!, String, String?, String![]);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public SliceItem(Object!, String, String?, java.util.List<java.lang.String!>);
     ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public SliceItem();
-    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public SliceItem(android.app.PendingIntent!, androidx.slice.Slice!, String!, String!, String![]!);
-    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public SliceItem(androidx.slice.SliceItem.ActionHandler!, androidx.slice.Slice!, String!, String!, String![]!);
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void addHint(String!);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public SliceItem(android.app.PendingIntent, androidx.slice.Slice?, String, String?, String![]);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public SliceItem(androidx.slice.SliceItem.ActionHandler, androidx.slice.Slice?, String, String?, String![]);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public void addHint(String);
     method public static android.text.ParcelableSpan createSensitiveSpan();
     method public void fireAction(android.content.Context?, android.content.Intent?) throws android.app.PendingIntent.CanceledException;
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean fireActionInternal(android.content.Context?, android.content.Intent?) throws android.app.PendingIntent.CanceledException;
-    method public android.app.PendingIntent! getAction();
-    method public String! getFormat();
+    method public android.app.PendingIntent? getAction();
+    method public String getFormat();
     method public java.util.List<java.lang.String!> getHints();
-    method public androidx.core.graphics.drawable.IconCompat! getIcon();
+    method public androidx.core.graphics.drawable.IconCompat? getIcon();
     method public int getInt();
     method public long getLong();
     method public CharSequence? getRedactedText();
-    method @RequiresApi(20) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.app.RemoteInput! getRemoteInput();
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public CharSequence! getSanitizedText();
-    method public androidx.slice.Slice! getSlice();
-    method public String! getSubType();
-    method public CharSequence! getText();
+    method @RequiresApi(20) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.app.RemoteInput? getRemoteInput();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public CharSequence? getSanitizedText();
+    method public androidx.slice.Slice? getSlice();
+    method public String? getSubType();
+    method public CharSequence? getText();
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public boolean hasAnyHints(java.lang.String!...);
-    method public boolean hasHint(String!);
+    method public boolean hasHint(String);
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface SliceItem.ActionHandler {
-    method public void onAction(androidx.slice.SliceItem!, android.content.Context!, android.content.Intent!);
+    method public void onAction(androidx.slice.SliceItem, android.content.Context?, android.content.Intent?);
   }
 
   @RequiresApi(19) public abstract class SliceManager {
@@ -120,7 +120,7 @@
     ctor public SliceSpec(String, int);
     method public boolean canRender(androidx.slice.SliceSpec);
     method public int getRevision();
-    method public String! getType();
+    method public String getType();
   }
 
   @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class SliceSpecs {
@@ -140,18 +140,18 @@
 package androidx.slice.compat {
 
   @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class CompatPermissionManager {
-    ctor public CompatPermissionManager(android.content.Context!, String!, int, String![]!);
-    method public int checkSlicePermission(android.net.Uri!, int, int);
-    method public void grantSlicePermission(android.net.Uri!, String!);
-    method public void revokeSlicePermission(android.net.Uri!, String!);
+    ctor public CompatPermissionManager(android.content.Context, String, int, String![]);
+    method public int checkSlicePermission(android.net.Uri, int, int);
+    method public void grantSlicePermission(android.net.Uri, String);
+    method public void revokeSlicePermission(android.net.Uri, String);
     field public static final String ALL_SUFFIX = "_all";
   }
 
   public static class CompatPermissionManager.PermissionState {
-    method public String! getKey();
-    method public boolean hasAccess(java.util.List<java.lang.String!>!);
+    method public String getKey();
+    method public boolean hasAccess(java.util.List<java.lang.String!>);
     method public boolean hasAllPermissions();
-    method public java.util.Set<java.lang.String!>! toPersistable();
+    method public java.util.Set<java.lang.String!> toPersistable();
   }
 
   @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class SliceProviderCompat {
@@ -212,10 +212,10 @@
     method public boolean isChecked();
     method public boolean isDefaultToggle();
     method public boolean isToggle();
-    method public androidx.slice.core.SliceAction! setChecked(boolean);
-    method public androidx.slice.core.SliceAction? setContentDescription(CharSequence);
+    method public androidx.slice.core.SliceAction setChecked(boolean);
+    method public androidx.slice.core.SliceAction setContentDescription(CharSequence);
     method public androidx.slice.core.SliceAction setKey(String);
-    method public androidx.slice.core.SliceAction! setPriority(@IntRange(from=0) int);
+    method public androidx.slice.core.SliceAction setPriority(@IntRange(from=0) int);
   }
 
   @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class SliceActionImpl implements androidx.slice.core.SliceAction {
@@ -223,11 +223,11 @@
     ctor public SliceActionImpl(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat, @androidx.slice.core.SliceHints.ImageMode int, CharSequence);
     ctor public SliceActionImpl(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat, CharSequence, boolean);
     ctor public SliceActionImpl(android.app.PendingIntent, CharSequence, boolean);
-    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public SliceActionImpl(androidx.slice.SliceItem!);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public SliceActionImpl(androidx.slice.SliceItem);
     method public androidx.slice.Slice buildPrimaryActionSlice(androidx.slice.Slice.Builder);
     method public androidx.slice.Slice buildSlice(androidx.slice.Slice.Builder);
     method public android.app.PendingIntent getAction();
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.slice.SliceItem! getActionItem();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.slice.SliceItem? getActionItem();
     method public CharSequence? getContentDescription();
     method public androidx.core.graphics.drawable.IconCompat? getIcon();
     method @androidx.slice.core.SliceHints.ImageMode public int getImageMode();
@@ -242,10 +242,10 @@
     method public boolean isToggle();
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static int parseImageMode(androidx.slice.SliceItem);
     method public void setActivity(boolean);
-    method public androidx.slice.core.SliceActionImpl! setChecked(boolean);
-    method public androidx.slice.core.SliceActionImpl? setContentDescription(CharSequence);
+    method public androidx.slice.core.SliceActionImpl setChecked(boolean);
+    method public androidx.slice.core.SliceAction? setContentDescription(CharSequence);
     method public androidx.slice.core.SliceActionImpl setKey(String);
-    method public androidx.slice.core.SliceActionImpl! setPriority(@IntRange(from=0) int);
+    method public androidx.slice.core.SliceActionImpl setPriority(@IntRange(from=0) int);
   }
 
   @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class SliceHints {
@@ -283,25 +283,25 @@
   }
 
   @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class SliceQuery {
-    method public static androidx.slice.SliceItem! find(androidx.slice.Slice!, String!, String!, String!);
-    method public static androidx.slice.SliceItem! find(androidx.slice.Slice!, String!);
-    method public static androidx.slice.SliceItem! find(androidx.slice.SliceItem!, String!);
-    method public static androidx.slice.SliceItem! find(androidx.slice.SliceItem!, String!, String!, String!);
-    method public static androidx.slice.SliceItem! find(androidx.slice.Slice!, String!, String![]!, String![]!);
-    method public static androidx.slice.SliceItem! find(androidx.slice.SliceItem!, String!, String![]!, String![]!);
-    method public static java.util.List<androidx.slice.SliceItem!>! findAll(androidx.slice.SliceItem!, String!);
-    method public static java.util.List<androidx.slice.SliceItem!>! findAll(androidx.slice.Slice!, String!, String!, String!);
-    method public static java.util.List<androidx.slice.SliceItem!>! findAll(androidx.slice.SliceItem!, String!, String!, String!);
-    method public static java.util.List<androidx.slice.SliceItem!>! findAll(androidx.slice.Slice!, String!, String![]!, String![]!);
-    method public static java.util.List<androidx.slice.SliceItem!>! findAll(androidx.slice.SliceItem!, String!, String![]!, String![]!);
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.slice.SliceItem! findItem(androidx.slice.Slice!, android.net.Uri!);
-    method public static androidx.slice.SliceItem! findNotContaining(androidx.slice.SliceItem!, java.util.List<androidx.slice.SliceItem!>!);
-    method public static androidx.slice.SliceItem! findSubtype(androidx.slice.Slice!, String!, String!);
-    method public static androidx.slice.SliceItem! findSubtype(androidx.slice.SliceItem!, String!, String!);
-    method public static androidx.slice.SliceItem! findTopLevelItem(androidx.slice.Slice!, String!, String!, String![]!, String![]!);
-    method public static boolean hasAnyHints(androidx.slice.SliceItem!, java.lang.String!...);
-    method public static boolean hasHints(androidx.slice.SliceItem!, java.lang.String!...);
-    method public static boolean hasHints(androidx.slice.Slice!, java.lang.String!...);
+    method public static androidx.slice.SliceItem? find(androidx.slice.Slice?, String?, String?, String?);
+    method public static androidx.slice.SliceItem? find(androidx.slice.Slice?, String?);
+    method public static androidx.slice.SliceItem? find(androidx.slice.SliceItem?, String?);
+    method public static androidx.slice.SliceItem? find(androidx.slice.SliceItem?, String?, String?, String?);
+    method public static androidx.slice.SliceItem? find(androidx.slice.Slice?, String?, String![]?, String![]?);
+    method public static androidx.slice.SliceItem? find(androidx.slice.SliceItem?, String?, String![]?, String![]?);
+    method public static java.util.List<androidx.slice.SliceItem!> findAll(androidx.slice.SliceItem, String?);
+    method public static java.util.List<androidx.slice.SliceItem!> findAll(androidx.slice.Slice, String?, String?, String?);
+    method public static java.util.List<androidx.slice.SliceItem!> findAll(androidx.slice.SliceItem, String?, String?, String?);
+    method public static java.util.List<androidx.slice.SliceItem!> findAll(androidx.slice.Slice, String?, String![]?, String![]?);
+    method public static java.util.List<androidx.slice.SliceItem!> findAll(androidx.slice.SliceItem, String?, String![]?, String![]?);
+    method public static androidx.slice.SliceItem? findItem(androidx.slice.Slice, android.net.Uri);
+    method public static androidx.slice.SliceItem? findNotContaining(androidx.slice.SliceItem?, java.util.List<androidx.slice.SliceItem!>);
+    method public static androidx.slice.SliceItem? findSubtype(androidx.slice.Slice?, String?, String?);
+    method public static androidx.slice.SliceItem? findSubtype(androidx.slice.SliceItem?, String?, String?);
+    method public static androidx.slice.SliceItem? findTopLevelItem(androidx.slice.Slice, String?, String?, String![]?, String![]?);
+    method public static boolean hasAnyHints(androidx.slice.SliceItem, java.lang.String!...);
+    method public static boolean hasHints(androidx.slice.SliceItem, java.lang.String!...);
+    method public static boolean hasHints(androidx.slice.Slice, java.lang.String!...);
   }
 
 }
diff --git a/slice/slice-core/src/androidTest/java/androidx/slice/SlicePermissionTest.java b/slice/slice-core/src/androidTest/java/androidx/slice/SlicePermissionTest.java
index b8b3ecf..88ed851 100644
--- a/slice/slice-core/src/androidTest/java/androidx/slice/SlicePermissionTest.java
+++ b/slice/slice-core/src/androidTest/java/androidx/slice/SlicePermissionTest.java
@@ -41,7 +41,7 @@
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
-@SdkSuppress(minSdkVersion = 19)
+@SdkSuppress(minSdkVersion = 24)
 public class SlicePermissionTest {
 
     private static final Uri BASE_URI = Uri.parse("content://androidx.slice.core.permission/");
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceConvert.java b/slice/slice-core/src/main/java/androidx/slice/SliceConvert.java
index da18bfa..71e9c23 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceConvert.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceConvert.java
@@ -25,11 +25,14 @@
 import static android.app.slice.SliceItem.FORMAT_SLICE;
 import static android.app.slice.SliceItem.FORMAT_TEXT;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.Bundle;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.collection.ArraySet;
@@ -50,7 +53,10 @@
      * Convert {@link androidx.slice.Slice androidx.slice.Slice} to
      * {@link android.app.slice.Slice android.app.slice.Slice}
      */
-    public static android.app.slice.Slice unwrap(androidx.slice.Slice slice) {
+    @SuppressWarnings({"ConstantConditions", "deprecation"})
+    @SuppressLint("WrongConstant") // conversion from platform definition
+    @Nullable
+    public static android.app.slice.Slice unwrap(@Nullable Slice slice) {
         if (slice == null || slice.getUri() == null) return null;
         android.app.slice.Slice.Builder builder = new android.app.slice.Slice.Builder(
                 slice.getUri(), unwrap(slice.getSpec()));
@@ -107,7 +113,10 @@
      * Convert {@link android.app.slice.Slice android.app.slice.Slice} to
      * {@link androidx.slice.Slice androidx.slice.Slice}
      */
-    public static androidx.slice.Slice wrap(android.app.slice.Slice slice, Context context) {
+    @SuppressWarnings("ConstantConditions") // conditional nullability
+    @Nullable
+    public static androidx.slice.Slice wrap(@Nullable android.app.slice.Slice slice,
+            @NonNull Context context) {
         if (slice == null || slice.getUri() == null) return null;
         androidx.slice.Slice.Builder builder = new androidx.slice.Slice.Builder(
                 slice.getUri());
@@ -162,9 +171,10 @@
     /**
      * @hide
      */
+    @NonNull
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     public static Set<androidx.slice.SliceSpec> wrap(
-            Set<android.app.slice.SliceSpec> supportedSpecs) {
+            @Nullable Set<android.app.slice.SliceSpec> supportedSpecs) {
         Set<androidx.slice.SliceSpec> ret = new ArraySet<>();
         if (supportedSpecs != null) {
             for (android.app.slice.SliceSpec spec : supportedSpecs) {
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceItem.java b/slice/slice-core/src/main/java/androidx/slice/SliceItem.java
index dcd668a..f9e12a3 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceItem.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceItem.java
@@ -27,6 +27,7 @@
 
 import static androidx.slice.Slice.appendHints;
 
+import android.annotation.SuppressLint;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
 import android.content.Context;
@@ -54,6 +55,7 @@
 import androidx.annotation.RestrictTo.Scope;
 import androidx.annotation.StringDef;
 import androidx.core.graphics.drawable.IconCompat;
+import androidx.core.util.ObjectsCompat;
 import androidx.core.util.Pair;
 import androidx.versionedparcelable.CustomVersionedParcelable;
 import androidx.versionedparcelable.NonParcelField;
@@ -110,27 +112,38 @@
     /**
      * @hide
      */
+    @NonNull
     @RestrictTo(Scope.LIBRARY)
     @ParcelField(value = 1, defaultValue = "androidx.slice.Slice.NO_HINTS")
-    protected @Slice.SliceHint String[] mHints = Slice.NO_HINTS;
+    @Slice.SliceHint String[] mHints = Slice.NO_HINTS;
+
+    @NonNull
     @ParcelField(value = 2, defaultValue = FORMAT_TEXT)
     String mFormat = FORMAT_TEXT;
+
+    @Nullable
     @ParcelField(value = 3, defaultValue = "null")
     String mSubType = null;
+
+    @Nullable
     @NonParcelField
     Object mObj;
+
     @NonParcelField
     CharSequence mSanitizedText;
 
+    @Nullable
     @ParcelField(4)
     SliceItemHolder mHolder;
 
     /**
      * @hide
      */
+    @SuppressWarnings("NullableProblems")
+    @SuppressLint("UnknownNullness") // obj cannot be correctly annotated
     @RestrictTo(Scope.LIBRARY_GROUP)
-    public SliceItem(Object obj, @SliceType String format, String subType,
-            @Slice.SliceHint String[] hints) {
+    public SliceItem(Object obj, @NonNull @SliceType String format, @Nullable String subType,
+            @NonNull @Slice.SliceHint String[] hints) {
         mHints = hints;
         mFormat = format;
         mSubType = subType;
@@ -140,9 +153,10 @@
     /**
      * @hide
      */
+    @SuppressLint("UnknownNullness") // obj cannot be correctly annotated
     @RestrictTo(Scope.LIBRARY_GROUP)
-    public SliceItem(Object obj, @SliceType String format, String subType,
-            @Slice.SliceHint List<String> hints) {
+    public SliceItem(Object obj, @NonNull @SliceType String format, @Nullable String subType,
+            @NonNull @Slice.SliceHint List<String> hints) {
         this (obj, format, subType, hints.toArray(new String[hints.size()]));
     }
 
@@ -158,17 +172,20 @@
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
-    public SliceItem(PendingIntent intent, Slice slice, String format, String subType,
-            @Slice.SliceHint String[] hints) {
+    public SliceItem(@NonNull PendingIntent intent, @Nullable Slice slice,
+            @NonNull @SliceType String format, @Nullable String subType,
+            @NonNull @Slice.SliceHint String[] hints) {
         this(new Pair<Object, Slice>(intent, slice), format, subType, hints);
     }
 
     /**
      * @hide
      */
+    @SuppressLint("LambdaLast")
     @RestrictTo(Scope.LIBRARY_GROUP)
-    public SliceItem(ActionHandler action, Slice slice, String format, String subType,
-            @Slice.SliceHint String[] hints) {
+    public SliceItem(@NonNull ActionHandler action, @Nullable Slice slice,
+            @NonNull @SliceType String format, @Nullable String subType,
+            @NonNull @Slice.SliceHint String[] hints) {
         this(new Pair<Object, Slice>(action, slice), format, subType, hints);
     }
 
@@ -184,6 +201,7 @@
     /**
      * @hide
      */
+    @SuppressWarnings("unused")
     @RestrictTo(Scope.LIBRARY)
     public @NonNull @Slice.SliceHint String[] getHintArray() {
         return mHints;
@@ -193,7 +211,7 @@
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
-    public void addHint(@Slice.SliceHint String hint) {
+    public void addHint(@Slice.SliceHint @NonNull String hint) {
         mHints = ArrayUtils.appendElement(String.class, mHints, hint);
     }
 
@@ -212,6 +230,7 @@
      * </ul>
      * @see #getSubType() ()
      */
+    @NonNull
     public @SliceType String getFormat() {
         return mFormat;
     }
@@ -225,6 +244,7 @@
      * {@link android.app.slice.Slice#SUBTYPE_MESSAGE}.
      * @see #getFormat()
      */
+    @Nullable
     public String getSubType() {
         return mSubType;
     }
@@ -232,6 +252,7 @@
     /**
      * @return The text held by this {@link android.app.slice.SliceItem#FORMAT_TEXT} SliceItem
      */
+    @Nullable
     public CharSequence getText() {
         return (CharSequence) mObj;
     }
@@ -242,6 +263,7 @@
      * ony spans that are unsupported by the androidx Slice renderer removed.
      */
     @RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
+    @Nullable
     public CharSequence getSanitizedText() {
         if (mSanitizedText == null) mSanitizedText = sanitizeText(getText());
         return mSanitizedText;
@@ -261,6 +283,7 @@
     /**
      * @return The icon held by this {@link android.app.slice.SliceItem#FORMAT_IMAGE} SliceItem
      */
+    @Nullable
     public IconCompat getIcon() {
         return (IconCompat) mObj;
     }
@@ -269,8 +292,10 @@
      * @return The pending intent held by this {@link android.app.slice.SliceItem#FORMAT_ACTION}
      * SliceItem
      */
+    @Nullable
     @SuppressWarnings("unchecked")
     public PendingIntent getAction() {
+        ObjectsCompat.requireNonNull(mObj, "Object must be non-null");
         Object action = ((Pair<Object, Slice>) mObj).first;
         if (action instanceof PendingIntent) {
             return (PendingIntent) action;
@@ -295,6 +320,7 @@
     @RestrictTo(Scope.LIBRARY_GROUP_PREFIX)
     public boolean fireActionInternal(@Nullable Context context, @Nullable Intent i)
             throws PendingIntent.CanceledException {
+        ObjectsCompat.requireNonNull(mObj, "Object must be non-null for FORMAT_ACTION");
         Object action = ((Pair<Object, Slice>) mObj).first;
         if (action instanceof PendingIntent) {
             ((PendingIntent) action).send(context, 0, i, null, null);
@@ -310,6 +336,7 @@
      * SliceItem
      * @hide
      */
+    @Nullable
     @RequiresApi(20)
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
     public RemoteInput getRemoteInput() {
@@ -320,6 +347,7 @@
      * @return The color held by this {@link android.app.slice.SliceItem#FORMAT_INT} SliceItem
      */
     public int getInt() {
+        ObjectsCompat.requireNonNull(mObj, "Object must be non-null for FORMAT_INT");
         return (Integer) mObj;
     }
 
@@ -327,8 +355,10 @@
      * @return The slice held by this {@link android.app.slice.SliceItem#FORMAT_ACTION} or
      * {@link android.app.slice.SliceItem#FORMAT_SLICE} SliceItem
      */
+    @Nullable
     @SuppressWarnings("unchecked")
     public Slice getSlice() {
+        ObjectsCompat.requireNonNull(mObj, "Object must be non-null for FORMAT_SLICE");
         if (FORMAT_ACTION.equals(getFormat())) {
             return ((Pair<Object, Slice>) mObj).second;
         }
@@ -340,6 +370,7 @@
      * SliceItem
      */
     public long getLong() {
+        ObjectsCompat.requireNonNull(mObj, "Object must be non-null for FORMAT_LONG");
         return (Long) mObj;
     }
 
@@ -347,7 +378,7 @@
      * @param hint The hint to check for
      * @return true if this item contains the given hint
      */
-    public boolean hasHint(@Slice.SliceHint String hint) {
+    public boolean hasHint(@NonNull @Slice.SliceHint String hint) {
         return ArrayUtils.contains(mHints, hint);
     }
 
@@ -355,7 +386,7 @@
      * @hide
      */
     @RestrictTo(Scope.LIBRARY)
-    public SliceItem(Bundle in) {
+    public SliceItem(@NonNull Bundle in) {
         mHints = in.getStringArray(HINTS);
         mFormat = in.getString(FORMAT);
         mSubType = in.getString(SUBTYPE);
@@ -364,8 +395,8 @@
 
     /**
      * @hide
-     * @return
      */
+    @NonNull
     @RestrictTo(Scope.LIBRARY)
     public Bundle toBundle() {
         Bundle b = new Bundle();
@@ -379,8 +410,9 @@
     /**
      * @hide
      */
+    @SuppressWarnings("unused")
     @RestrictTo(Scope.LIBRARY)
-    public boolean hasHints(@Slice.SliceHint String[] hints) {
+    public boolean hasHints(@Nullable @Slice.SliceHint String[] hints) {
         if (hints == null) return true;
         for (String hint : hints) {
             if (!TextUtils.isEmpty(hint) && !ArrayUtils.contains(mHints, hint)) {
@@ -394,7 +426,7 @@
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
-    public boolean hasAnyHints(@Slice.SliceHint String... hints) {
+    public boolean hasAnyHints(@Nullable @Slice.SliceHint String... hints) {
         if (hints == null) return false;
         for (String hint : hints) {
             if (ArrayUtils.contains(mHints, hint)) {
@@ -405,7 +437,7 @@
     }
 
     @SuppressWarnings("unchecked")
-    private void writeObj(Bundle dest, Object obj, String type) {
+    private void writeObj(@NonNull Bundle dest, Object obj, @NonNull String type) {
         switch (type) {
             case FORMAT_IMAGE:
                 dest.putBundle(OBJ, ((IconCompat) obj).toBundle());
@@ -424,9 +456,11 @@
                 dest.putCharSequence(OBJ, (CharSequence) obj);
                 break;
             case FORMAT_INT:
+                ObjectsCompat.requireNonNull(mObj, "Object must be non-null for FORMAT_INT");
                 dest.putInt(OBJ, (Integer) mObj);
                 break;
             case FORMAT_LONG:
+                ObjectsCompat.requireNonNull(mObj, "Object must be non-null for FORMAT_LONG");
                 dest.putLong(OBJ, (Long) mObj);
                 break;
             case FORMAT_BUNDLE:
@@ -434,8 +468,8 @@
         }
     }
 
-    @SuppressWarnings("deprecation")
-    private static Object readObj(String type, Bundle in) {
+    @Nullable
+    private static Object readObj(@NonNull String type, @NonNull Bundle in) {
         switch (type) {
             case FORMAT_IMAGE:
                 return IconCompat.createFromBundle(in.getBundle(OBJ));
@@ -462,8 +496,9 @@
     /**
      * @hide
      */
+    @NonNull
     @RestrictTo(Scope.LIBRARY)
-    public static String typeToString(String format) {
+    public static String typeToString(@NonNull String format) {
         switch (format) {
             case FORMAT_SLICE:
                 return "Slice";
@@ -486,6 +521,7 @@
     /**
      * @return A string representation of this slice item.
      */
+    @NonNull
     @Override
     public String toString() {
         return toString("");
@@ -495,9 +531,10 @@
      * @return A string representation of this slice item.
      * @hide
      */
+    @NonNull
     @RestrictTo(Scope.LIBRARY)
     @SuppressWarnings("unchecked")
-    public String toString(String indent) {
+    public String toString(@NonNull String indent) {
         StringBuilder sb = new StringBuilder();
         sb.append(indent);
         sb.append(getFormat());
@@ -513,12 +550,18 @@
         }
         final String nextIndent = indent + "  ";
         switch (getFormat()) {
-            case FORMAT_SLICE:
+            case FORMAT_SLICE: {
+                Slice slice = getSlice();
+                ObjectsCompat.requireNonNull(slice, "Slice must be non-null for FORMAT_SLICE");
                 sb.append("{\n");
-                sb.append(getSlice().toString(nextIndent));
+                sb.append(slice.toString(nextIndent));
                 sb.append('\n').append(indent).append('}');
                 break;
-            case FORMAT_ACTION:
+            }
+            case FORMAT_ACTION: {
+                Slice slice = getSlice();
+                ObjectsCompat.requireNonNull(mObj, "Object must be non-null for FORMAT_ACTION");
+                ObjectsCompat.requireNonNull(slice, "Slice must be non-null for FORMAT_SLICE");
                 // Not using getAction because the action can actually be other types.
                 Object action = ((Pair<Object, Slice>) mObj).first;
                 sb.append('[').append(action).append("] ");
@@ -526,6 +569,7 @@
                 sb.append(getSlice().toString(nextIndent));
                 sb.append('\n').append(indent).append('}');
                 break;
+            }
             case FORMAT_TEXT:
                 sb.append('"').append(getText()).append('"');
                 break;
@@ -591,6 +635,7 @@
         return new Annotation(SLICE_CONTENT, SLICE_CONTENT_SENSITIVE);
     }
 
+    @NonNull
     private static String layoutDirectionToString(int layoutDirection) {
         switch (layoutDirection) {
             case android.util.LayoutDirection.LTR:
@@ -618,7 +663,7 @@
         }
     }
 
-    private static boolean isRedactionNeeded(Spanned text) {
+    private static boolean isRedactionNeeded(@NonNull Spanned text) {
         for (Annotation span : text.getSpans(0, text.length(), Annotation.class)) {
             if (SLICE_CONTENT.equals(span.getKey())
                     && SLICE_CONTENT_SENSITIVE.equals(span.getValue())) {
@@ -628,7 +673,8 @@
         return false;
     }
 
-    private static CharSequence redactSpannableText(Spannable text) {
+    @NonNull
+    private static CharSequence redactSpannableText(@NonNull Spannable text) {
         Spanned out = text;
         for (Annotation span : text.getSpans(0, text.length(), Annotation.class)) {
             if (!SLICE_CONTENT.equals(span.getKey())
@@ -645,6 +691,7 @@
         return out;
     }
 
+    @NonNull
     private static String createRedacted(final int n) {
         StringBuilder s = new StringBuilder();
         for (int i = 0; i < n; i++) {
@@ -653,7 +700,8 @@
         return s.toString();
     }
 
-    private static CharSequence sanitizeText(CharSequence text) {
+    @Nullable
+    private static CharSequence sanitizeText(@Nullable CharSequence text) {
         if (text instanceof Spannable) {
             fixSpannableText((Spannable) text);
             return text;
@@ -667,14 +715,14 @@
         }
     }
 
-    private static boolean checkSpannedText(Spanned text) {
+    private static boolean checkSpannedText(@NonNull Spanned text) {
         for (Object span : text.getSpans(0, text.length(), Object.class)) {
             if (!checkSpan(span)) return false;
         }
         return true;
     }
 
-    private static void fixSpannableText(Spannable text) {
+    private static void fixSpannableText(@NonNull Spannable text) {
         for (Object span : text.getSpans(0, text.length(), Object.class)) {
             Object fixedSpan = fixSpan(span);
             if (fixedSpan == span) continue;
@@ -700,6 +748,7 @@
                 || span instanceof StyleSpan;
     }
 
+    @Nullable
     private static Object fixSpan(Object span) {
         return checkSpan(span) ? span : null;
     }
@@ -712,6 +761,6 @@
         /**
          * Called when a pending intent would be sent on a real slice.
          */
-        void onAction(SliceItem item, Context context, Intent intent);
+        void onAction(@NonNull SliceItem item, @Nullable Context context, @Nullable Intent intent);
     }
 }
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceItemHolder.java b/slice/slice-core/src/main/java/androidx/slice/SliceItemHolder.java
index 9e4a7ac..1cdd23398 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceItemHolder.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceItemHolder.java
@@ -25,11 +25,14 @@
 import static android.app.slice.SliceItem.FORMAT_SLICE;
 import static android.app.slice.SliceItem.FORMAT_TEXT;
 
+import android.annotation.SuppressLint;
 import android.app.PendingIntent;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.text.Spanned;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.text.HtmlCompat;
@@ -51,28 +54,41 @@
 public class SliceItemHolder implements VersionedParcelable {
 
     public static final Object sSerializeLock = new Object();
+
+    @Nullable
     public static HolderHandler sHandler;
 
     // VersionedParcelable fields for custom serialization.
+    @Nullable
     @ParcelField(value = 1, defaultValue = "null")
     public VersionedParcelable mVersionedParcelable = null;
+
+    @Nullable
     @ParcelField(value = 2, defaultValue = "null")
     Parcelable mParcelable = null;
+
     @NonParcelField
     Object mCallback;
+
+    @Nullable
     @ParcelField(value = 3, defaultValue = "null")
     String mStr = null;
+
     @ParcelField(value = 4, defaultValue = "0")
     int mInt = 0;
+
     @ParcelField(value = 5, defaultValue = "0")
     long mLong = 0;
+
+    @Nullable
     @ParcelField(value = 6, defaultValue = "null")
     Bundle mBundle = null;
 
+    @Nullable
     @NonParcelField
     private SliceItemPool mPool;
 
-    SliceItemHolder(SliceItemPool pool) {
+    SliceItemHolder(@NonNull SliceItemPool pool) {
         mPool = pool;
     }
 
@@ -86,7 +102,8 @@
     }
 
     @SuppressWarnings("unchecked")
-    public SliceItemHolder(String format, Object mObj, boolean isStream) {
+    @SuppressLint("UnknownNullness") // mObj cannot be correctly annotated
+    public SliceItemHolder(@NonNull String format, Object mObj, boolean isStream) {
         switch (format) {
             case FORMAT_ACTION:
                 if (((Pair<Object, Slice>) mObj).first instanceof PendingIntent) {
@@ -125,7 +142,8 @@
     /**
      * Gets object that should be held by SliceItem.
      */
-    public Object getObj(String format) {
+    @Nullable
+    public Object getObj(@NonNull String format) {
         if (SliceItemHolder.sHandler != null) {
             SliceItemHolder.sHandler.handle(this, format);
         }
@@ -159,7 +177,10 @@
      * Callback that gets to participate in the serialization process for SliceItems.
      */
     public interface HolderHandler {
-        void handle(SliceItemHolder holder, String format);
+        /**
+         * Called during the serialization process for SliceItems.
+         */
+        void handle(@NonNull SliceItemHolder holder, @NonNull String format);
     }
 
     /**
@@ -172,6 +193,7 @@
         /**
          * Acquire an item from the pool.
          */
+        @NonNull
         public SliceItemHolder get() {
             if (mCached.size() > 0) {
                 return mCached.remove(mCached.size() - 1);
@@ -182,7 +204,7 @@
         /**
          * Send an object back to the pool.
          */
-        public void release(SliceItemHolder sliceItemHolder) {
+        public void release(@NonNull SliceItemHolder sliceItemHolder) {
             sliceItemHolder.mParcelable = null;
             sliceItemHolder.mCallback = null;
             sliceItemHolder.mVersionedParcelable = null;
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceManagerWrapper.java b/slice/slice-core/src/main/java/androidx/slice/SliceManagerWrapper.java
index 8099984..349dc92 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceManagerWrapper.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceManagerWrapper.java
@@ -16,6 +16,7 @@
 
 package androidx.slice;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Build;
@@ -56,6 +57,7 @@
         return SliceConvert.wrap(mManager.getPinnedSpecs(uri));
     }
 
+    @SuppressLint("WrongConstant") // conversion from platform definition
     @Override
     @PermissionChecker.PermissionResult
     public int checkSlicePermission(@NonNull Uri uri, int pid, int uid) {
@@ -72,6 +74,7 @@
         mManager.revokeSlicePermission(toPackage, uri);
     }
 
+    @NonNull
     @Override
     public List<Uri> getPinnedSlices() {
         return mManager.getPinnedSlices();
diff --git a/slice/slice-core/src/main/java/androidx/slice/SliceSpec.java b/slice/slice-core/src/main/java/androidx/slice/SliceSpec.java
index 747b136..c0aaebe 100644
--- a/slice/slice-core/src/main/java/androidx/slice/SliceSpec.java
+++ b/slice/slice-core/src/main/java/androidx/slice/SliceSpec.java
@@ -69,6 +69,7 @@
     /**
      * Gets the type of the version.
      */
+    @NonNull
     public String getType() {
         return mType;
     }
diff --git a/slice/slice-core/src/main/java/androidx/slice/compat/CompatPermissionManager.java b/slice/slice-core/src/main/java/androidx/slice/compat/CompatPermissionManager.java
index 0a740d3..52259f6 100644
--- a/slice/slice-core/src/main/java/androidx/slice/compat/CompatPermissionManager.java
+++ b/slice/slice-core/src/main/java/androidx/slice/compat/CompatPermissionManager.java
@@ -26,6 +26,7 @@
 import android.net.Uri;
 import android.text.TextUtils;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.collection.ArraySet;
@@ -41,17 +42,20 @@
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 @RequiresApi(19)
 public class CompatPermissionManager {
-
-    private static final String TAG = "CompatPermissionManager";
     public static final String ALL_SUFFIX = "_all";
 
+    private final Object mPrefsLock = new Object();
+
+    @NonNull
     private final Context mContext;
     private final String mPrefsName;
     private final int mMyUid;
+
+    @NonNull
     private final String[] mAutoGrantPermissions;
 
-    public CompatPermissionManager(Context context, String prefsName, int myUid,
-            String[] autoGrantPermissions) {
+    public CompatPermissionManager(@NonNull Context context, @NonNull String prefsName, int myUid,
+            @NonNull String[] autoGrantPermissions) {
         mContext = context;
         mPrefsName = prefsName;
         mMyUid = myUid;
@@ -63,7 +67,7 @@
     }
 
     @SuppressLint("WrongConstant")
-    public int checkSlicePermission(Uri uri, int pid, int uid) {
+    public int checkSlicePermission(@NonNull Uri uri, int pid, int uid) {
         if (uid == mMyUid) {
             return PERMISSION_GRANTED;
         }
@@ -85,35 +89,47 @@
         return mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
     }
 
-    private int checkSlicePermission(Uri uri, String pkg) {
+    /**
+     * Checks state of slice permission for the specified package.
+     */
+    private int checkSlicePermission(@NonNull Uri uri, @NonNull String pkg) {
         PermissionState state = getPermissionState(pkg, uri.getAuthority());
         return state.hasAccess(uri.getPathSegments()) ? PERMISSION_GRANTED : PERMISSION_DENIED;
     }
 
-    public void grantSlicePermission(Uri uri, String toPkg) {
+    /**
+     * Grants slice permission to the specified package.
+     */
+    public void grantSlicePermission(@NonNull Uri uri, @NonNull String toPkg) {
         PermissionState state = getPermissionState(toPkg, uri.getAuthority());
         if (state.addPath(uri.getPathSegments())) {
             persist(state);
         }
     }
 
-    public void revokeSlicePermission(Uri uri, String toPkg) {
+    /**
+     * Revoked slice permission from the specified package.
+     */
+    public void revokeSlicePermission(@NonNull Uri uri, @NonNull String toPkg) {
         PermissionState state = getPermissionState(toPkg, uri.getAuthority());
         if (state.removePath(uri.getPathSegments())) {
             persist(state);
         }
     }
 
-    private synchronized void persist(PermissionState state) {
-        getPrefs().edit()
-                .putStringSet(state.getKey(), state.toPersistable())
-                .putBoolean(state.getKey() + ALL_SUFFIX, state.hasAllPermissions())
-                .apply();
+    private void persist(@NonNull PermissionState state) {
+        synchronized (mPrefsLock) {
+            getPrefs().edit()
+                    .putStringSet(state.getKey(), state.toPersistable())
+                    .putBoolean(state.getKey() + ALL_SUFFIX, state.hasAllPermissions())
+                    .apply();
+        }
     }
 
-    private PermissionState getPermissionState(String pkg, String authority) {
+    @NonNull
+    private PermissionState getPermissionState(@NonNull String pkg, @NonNull String authority) {
         String key = pkg + "_" + authority;
-        Set<String> grant = getPrefs().getStringSet(key, Collections.<String>emptySet());
+        Set<String> grant = getPrefs().getStringSet(key, Collections.emptySet());
         boolean hasAllPermissions = getPrefs().getBoolean(key + ALL_SUFFIX, false);
         return new PermissionState(grant, key, hasAllPermissions);
     }
@@ -123,7 +139,8 @@
         private final ArraySet<String[]> mPaths = new ArraySet<>();
         private final String mKey;
 
-        PermissionState(Set<String> grant, String key, boolean hasAllPermissions) {
+        PermissionState(@NonNull Set<String> grant, @NonNull String key,
+                boolean hasAllPermissions) {
             if (hasAllPermissions) {
                 mPaths.add(new String[0]);
             } else {
@@ -135,13 +152,15 @@
         }
 
         public boolean hasAllPermissions() {
-            return hasAccess(Collections.<String>emptyList());
+            return hasAccess(Collections.emptyList());
         }
 
+        @NonNull
         public String getKey() {
             return mKey;
         }
 
+        @NonNull
         public Set<String> toPersistable() {
             ArraySet<String> ret = new ArraySet<>();
             for (String[] path : mPaths) {
@@ -150,8 +169,8 @@
             return ret;
         }
 
-        public boolean hasAccess(List<String> path) {
-            String[] inPath = path.toArray(new String[path.size()]);
+        public boolean hasAccess(@NonNull List<String> path) {
+            String[] inPath = path.toArray(new String[0]);
             for (String[] p : mPaths) {
                 if (isPathPrefixMatch(p, inPath)) {
                     return true;
@@ -160,8 +179,8 @@
             return false;
         }
 
-        boolean addPath(List<String> path) {
-            String[] pathSegs = path.toArray(new String[path.size()]);
+        boolean addPath(@NonNull List<String> path) {
+            String[] pathSegs = path.toArray(new String[0]);
             for (int i = mPaths.size() - 1; i >= 0; i--) {
                 String[] existing = mPaths.valueAt(i);
                 if (isPathPrefixMatch(existing, pathSegs)) {
@@ -176,9 +195,9 @@
             return true;
         }
 
-        boolean removePath(List<String> path) {
+        boolean removePath(@NonNull List<String> path) {
             boolean changed = false;
-            String[] pathSegs = path.toArray(new String[path.size()]);
+            String[] pathSegs = path.toArray(new String[0]);
             for (int i = mPaths.size() - 1; i >= 0; i--) {
                 String[] existing = mPaths.valueAt(i);
                 if (isPathPrefixMatch(pathSegs, existing)) {
@@ -189,7 +208,7 @@
             return changed;
         }
 
-        private boolean isPathPrefixMatch(String[] prefix, String[] path) {
+        private boolean isPathPrefixMatch(@NonNull String[] prefix, @NonNull String[] path) {
             final int prefixSize = prefix.length;
             if (path.length < prefixSize) return false;
 
@@ -202,7 +221,7 @@
             return true;
         }
 
-        private String encodeSegments(String[] s) {
+        private String encodeSegments(@NonNull String[] s) {
             String[] out = new String[s.length];
             for (int i = 0; i < s.length; i++) {
                 out[i] = Uri.encode(s[i]);
@@ -210,7 +229,8 @@
             return TextUtils.join("/", out);
         }
 
-        private String[] decodeSegments(String s) {
+        @NonNull
+        private String[] decodeSegments(@NonNull String s) {
             String[] sets = s.split("/", -1);
             for (int i = 0; i < sets.length; i++) {
                 sets[i] = Uri.decode(sets[i]);
diff --git a/slice/slice-core/src/main/java/androidx/slice/compat/CompatPinnedList.java b/slice/slice-core/src/main/java/androidx/slice/compat/CompatPinnedList.java
index 3a4ebb3..876ec00 100644
--- a/slice/slice-core/src/main/java/androidx/slice/compat/CompatPinnedList.java
+++ b/slice/slice-core/src/main/java/androidx/slice/compat/CompatPinnedList.java
@@ -22,6 +22,8 @@
 import android.os.SystemClock;
 import android.text.TextUtils;
 
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
@@ -53,10 +55,15 @@
     // Its probably safe to assume the device can't boot twice within 2 secs.
     private static final long BOOT_THRESHOLD = 2000;
 
+    private final Object mPrefsLock = new Object();
+
+    @NonNull
     private final Context mContext;
+
+    @NonNull
     private final String mPrefsName;
 
-    public CompatPinnedList(Context context, String prefsName) {
+    public CompatPinnedList(@NonNull Context context, @NonNull String prefsName) {
         mContext = context;
         mPrefsName = prefsName;
     }
@@ -77,6 +84,7 @@
     /**
      * Get pinned specs
      */
+    @NonNull
     public List<Uri> getPinnedSlices() {
         List<Uri> pinned = new ArrayList<>();
         for (String key : getPrefs().getAll().keySet()) {
@@ -91,38 +99,44 @@
     }
 
     private Set<String> getPins(Uri uri) {
-        return getPrefs().getStringSet(PIN_PREFIX + uri.toString(), new ArraySet<String>());
+        return getPrefs().getStringSet(PIN_PREFIX + uri.toString(), new ArraySet<>());
     }
 
     /**
      * Get the list of specs for a pinned Uri.
      */
-    public synchronized ArraySet<SliceSpec> getSpecs(Uri uri) {
-        ArraySet<SliceSpec> specs = new ArraySet<>();
-        SharedPreferences prefs = getPrefs();
-        String specNamesStr = prefs.getString(SPEC_NAME_PREFIX + uri.toString(), null);
-        String specRevsStr = prefs.getString(SPEC_REV_PREFIX + uri.toString(), null);
-        if (TextUtils.isEmpty(specNamesStr) || TextUtils.isEmpty(specRevsStr)) {
-            return new ArraySet<>();
+    @NonNull
+    public ArraySet<SliceSpec> getSpecs(@NonNull Uri uri) {
+        synchronized (mPrefsLock) {
+            ArraySet<SliceSpec> specs = new ArraySet<>();
+            SharedPreferences prefs = getPrefs();
+            String specNamesStr = prefs.getString(SPEC_NAME_PREFIX + uri, null);
+            String specRevsStr = prefs.getString(SPEC_REV_PREFIX + uri, null);
+            if (TextUtils.isEmpty(specNamesStr) || TextUtils.isEmpty(specRevsStr)) {
+                return new ArraySet<>();
+            }
+            String[] specNames = specNamesStr.split(",", -1);
+            String[] specRevs = specRevsStr.split(",", -1);
+            if (specNames.length != specRevs.length) {
+                return new ArraySet<>();
+            }
+            for (int i = 0; i < specNames.length; i++) {
+                specs.add(new SliceSpec(specNames[i], Integer.parseInt(specRevs[i])));
+            }
+            return specs;
         }
-        String[] specNames = specNamesStr.split(",", -1);
-        String[] specRevs = specRevsStr.split(",", -1);
-        if (specNames.length != specRevs.length) {
-            return new ArraySet<>();
-        }
-        for (int i = 0; i < specNames.length; i++) {
-            specs.add(new SliceSpec(specNames[i], Integer.parseInt(specRevs[i])));
-        }
-        return specs;
     }
 
-    private void setPins(Uri uri, Set<String> pins) {
+    @GuardedBy("mPrefsLock")
+    private void setPinsLocked(@NonNull Uri uri, @NonNull Set<String> pins) {
         getPrefs().edit()
-                .putStringSet(PIN_PREFIX + uri.toString(), pins)
+                .putStringSet(PIN_PREFIX + uri, pins)
                 .apply();
     }
 
-    private void setSpecs(Uri uri, ArraySet<SliceSpec> specs) {
+    @SuppressWarnings("ConstantConditions") // implied non-null type use
+    @GuardedBy("mPrefsLock")
+    private void setSpecsLocked(@NonNull Uri uri, @NonNull ArraySet<SliceSpec> specs) {
         String[] specNames = new String[specs.size()];
         String[] specRevs = new String[specs.size()];
         for (int i = 0; i < specs.size(); i++) {
@@ -130,8 +144,8 @@
             specRevs[i] = String.valueOf(specs.valueAt(i).getRevision());
         }
         getPrefs().edit()
-                .putString(SPEC_NAME_PREFIX + uri.toString(), TextUtils.join(",", specNames))
-                .putString(SPEC_REV_PREFIX + uri.toString(), TextUtils.join(",", specRevs))
+                .putString(SPEC_NAME_PREFIX + uri, TextUtils.join(",", specNames))
+                .putString(SPEC_REV_PREFIX + uri, TextUtils.join(",", specRevs))
                 .apply();
     }
 
@@ -144,34 +158,39 @@
      * Adds a pin for a specific uri/pkg pair and returns true if the
      * uri was not previously pinned.
      */
-    public synchronized boolean addPin(Uri uri, String pkg, Set<SliceSpec> specs) {
-        Set<String> pins = getPins(uri);
-        boolean wasNotPinned = pins.isEmpty();
-        pins.add(pkg);
-        setPins(uri, pins);
-        if (wasNotPinned) {
-            setSpecs(uri, new ArraySet<>(specs));
-        } else {
-            setSpecs(uri, mergeSpecs(getSpecs(uri), specs));
+    public boolean addPin(@NonNull Uri uri, @NonNull String pkg, @NonNull Set<SliceSpec> specs) {
+        synchronized (mPrefsLock) {
+            Set<String> pins = getPins(uri);
+            boolean wasNotPinned = pins.isEmpty();
+            pins.add(pkg);
+            setPinsLocked(uri, pins);
+            if (wasNotPinned) {
+                setSpecsLocked(uri, new ArraySet<>(specs));
+            } else {
+                setSpecsLocked(uri, mergeSpecs(getSpecs(uri), specs));
+            }
+            return wasNotPinned;
         }
-        return wasNotPinned;
     }
 
     /**
      * Removes a pin for a specific uri/pkg pair and returns true if the
      * uri is no longer pinned (but was).
      */
-    public synchronized boolean removePin(Uri uri, String pkg) {
-        Set<String> pins = getPins(uri);
-        if (pins.isEmpty() || !pins.contains(pkg)) {
-            return false;
+    public boolean removePin(@NonNull Uri uri, @NonNull String pkg) {
+        synchronized (mPrefsLock) {
+            Set<String> pins = getPins(uri);
+            if (pins.isEmpty() || !pins.contains(pkg)) {
+                return false;
+            }
+            pins.remove(pkg);
+            setPinsLocked(uri, pins);
+            setSpecsLocked(uri, new ArraySet<>());
+            return pins.size() == 0;
         }
-        pins.remove(pkg);
-        setPins(uri, pins);
-        setSpecs(uri, new ArraySet<SliceSpec>());
-        return pins.size() == 0;
     }
 
+    @SuppressWarnings("ConstantConditions") // implied non-null type use
     private static ArraySet<SliceSpec> mergeSpecs(ArraySet<SliceSpec> specs,
             Set<SliceSpec> supportedSpecs) {
         for (int i = 0; i < specs.size(); i++) {
diff --git a/slice/slice-core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java b/slice/slice-core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java
index a659a18..af0d22d 100644
--- a/slice/slice-core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java
+++ b/slice/slice-core/src/main/java/androidx/slice/compat/SlicePermissionActivity.java
@@ -30,6 +30,7 @@
 import android.util.Log;
 import android.widget.TextView;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.appcompat.app.AlertDialog;
@@ -52,17 +53,15 @@
 
     private Uri mUri;
     private String mCallingPkg;
-    private String mProviderPkg;
     private AlertDialog mDialog;
 
     @Override
-    @SuppressWarnings("deprecation")
-    protected void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         mUri = getIntent().getParcelableExtra(SliceProviderCompat.EXTRA_BIND_URI);
         mCallingPkg = getIntent().getStringExtra(SliceProviderCompat.EXTRA_PKG);
-        mProviderPkg = getIntent().getStringExtra(SliceProviderCompat.EXTRA_PROVIDER_PKG);
+        String providerPkg = getIntent().getStringExtra(SliceProviderCompat.EXTRA_PROVIDER_PKG);
 
         try {
             PackageManager pm = getPackageManager();
@@ -70,7 +69,7 @@
                     loadSafeLabel(pm, pm.getApplicationInfo(mCallingPkg, 0))
                     .toString());
             CharSequence app2 = BidiFormatter.getInstance().unicodeWrap(
-                    loadSafeLabel(pm, pm.getApplicationInfo(mProviderPkg, 0))
+                    loadSafeLabel(pm, pm.getApplicationInfo(providerPkg, 0))
                     .toString());
             mDialog = new AlertDialog.Builder(this)
                     .setTitle(getString(R.string.abc_slice_permission_title, app1, app2))
diff --git a/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderCompat.java b/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
index b9fee1f..f2ba233 100644
--- a/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
+++ b/slice/slice-core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
@@ -42,6 +42,7 @@
 import android.os.StrictMode;
 import android.util.Log;
 
+import androidx.annotation.DoNotInline;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
@@ -106,8 +107,8 @@
     @SuppressWarnings("WeakerAccess") /* synthetic access */
     String mCallback;
     private final SliceProvider mProvider;
-    private CompatPinnedList mPinnedList;
-    private CompatPermissionManager mPermissionManager;
+    private final CompatPinnedList mPinnedList;
+    private final CompatPermissionManager mPermissionManager;
 
     public SliceProviderCompat(@NonNull SliceProvider provider,
             @NonNull CompatPermissionManager permissionManager, @NonNull Context context) {
@@ -115,7 +116,7 @@
         mContext = context;
         String prefsFile = DATA_PREFIX + "androidx.slice.compat.SliceProviderCompat";
         SharedPreferences allFiles = mContext.getSharedPreferences(ALL_FILES, 0);
-        Set<String> files = allFiles.getStringSet(ALL_FILES, Collections.<String>emptySet());
+        Set<String> files = allFiles.getStringSet(ALL_FILES, Collections.emptySet());
         if (!files.contains(prefsFile)) {
             // Make sure this is editable.
             files = new ArraySet<>(files);
@@ -141,29 +142,30 @@
      * Called by SliceProvider when compat is needed.
      */
     @Nullable
-    @SuppressWarnings("deprecation")
     public Bundle call(@NonNull String method, @Nullable String arg, @NonNull Bundle extras) {
-        if (method.equals(METHOD_SLICE)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
-            mProvider.validateIncomingAuthority(uri.getAuthority());
-            Set<SliceSpec> specs = getSpecs(extras);
+        switch (method) {
+            case METHOD_SLICE: {
+                Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+                mProvider.validateIncomingAuthority(uri.getAuthority());
+                Set<SliceSpec> specs = getSpecs(extras);
 
-            Slice s = handleBindSlice(uri, specs, getCallingPackage());
-            Bundle b = new Bundle();
-            if (ARG_SUPPORTS_VERSIONED_PARCELABLE.equals(arg)) {
-                synchronized (SliceItemHolder.sSerializeLock) {
-                    b.putParcelable(EXTRA_SLICE, s != null ? ParcelUtils.toParcelable(s) : null);
+                Slice s = handleBindSlice(uri, specs, getCallingPackage());
+                Bundle b = new Bundle();
+                if (ARG_SUPPORTS_VERSIONED_PARCELABLE.equals(arg)) {
+                    synchronized (SliceItemHolder.sSerializeLock) {
+                        b.putParcelable(EXTRA_SLICE,
+                                s != null ? ParcelUtils.toParcelable(s) : null);
+                    }
+                } else {
+                    b.putParcelable(EXTRA_SLICE, s != null ? s.toBundle() : null);
                 }
-            } else {
-                b.putParcelable(EXTRA_SLICE, s != null ? s.toBundle() : null);
+                return b;
             }
-            return b;
-        } else if (method.equals(METHOD_MAP_INTENT)) {
-            Intent intent = extras.getParcelable(EXTRA_INTENT);
-            Uri uri = mProvider.onMapIntentToUri(intent);
-            mProvider.validateIncomingAuthority(uri.getAuthority());
-            Bundle b = new Bundle();
-            if (uri != null) {
+            case METHOD_MAP_INTENT: {
+                Intent intent = extras.getParcelable(EXTRA_INTENT);
+                Uri uri = mProvider.onMapIntentToUri(intent);
+                mProvider.validateIncomingAuthority(uri.getAuthority());
+                Bundle b = new Bundle();
                 Set<SliceSpec> specs = getSpecs(extras);
                 Slice s = handleBindSlice(uri, specs, getCallingPackage());
                 if (ARG_SUPPORTS_VERSIONED_PARCELABLE.equals(arg)) {
@@ -174,75 +176,85 @@
                 } else {
                     b.putParcelable(EXTRA_SLICE, s != null ? s.toBundle() : null);
                 }
-            } else {
-                b.putParcelable(EXTRA_SLICE, null);
+                return b;
             }
-            return b;
-        } else if (method.equals(METHOD_MAP_ONLY_INTENT)) {
-            Intent intent = extras.getParcelable(EXTRA_INTENT);
-            Uri uri = mProvider.onMapIntentToUri(intent);
-            mProvider.validateIncomingAuthority(uri.getAuthority());
-            Bundle b = new Bundle();
-            b.putParcelable(EXTRA_SLICE, uri);
-            return b;
-        } else if (method.equals(METHOD_PIN)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
-            mProvider.validateIncomingAuthority(uri.getAuthority());
-            Set<SliceSpec> specs = getSpecs(extras);
-            String pkg = extras.getString(EXTRA_PKG);
-            if (mPinnedList.addPin(uri, pkg, specs)) {
-                handleSlicePinned(uri);
+            case METHOD_MAP_ONLY_INTENT: {
+                Intent intent = extras.getParcelable(EXTRA_INTENT);
+                Uri uri = mProvider.onMapIntentToUri(intent);
+                mProvider.validateIncomingAuthority(uri.getAuthority());
+                Bundle b = new Bundle();
+                b.putParcelable(EXTRA_SLICE, uri);
+                return b;
             }
-            return null;
-        } else if (method.equals(METHOD_UNPIN)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
-            mProvider.validateIncomingAuthority(uri.getAuthority());
-            String pkg = extras.getString(EXTRA_PKG);
-            if (mPinnedList.removePin(uri, pkg)) {
-                handleSliceUnpinned(uri);
+            case METHOD_PIN: {
+                Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+                mProvider.validateIncomingAuthority(uri.getAuthority());
+                Set<SliceSpec> specs = getSpecs(extras);
+                String pkg = extras.getString(EXTRA_PKG);
+                if (mPinnedList.addPin(uri, pkg, specs)) {
+                    handleSlicePinned(uri);
+                }
+                return null;
             }
-            return null;
-        } else if (method.equals(METHOD_GET_PINNED_SPECS)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
-            mProvider.validateIncomingAuthority(uri.getAuthority());
-            Bundle b = new Bundle();
-            ArraySet<SliceSpec> specs = mPinnedList.getSpecs(uri);
-            if (specs.size() == 0) {
-                throw new IllegalStateException(uri + " is not pinned");
+            case METHOD_UNPIN: {
+                Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+                mProvider.validateIncomingAuthority(uri.getAuthority());
+                String pkg = extras.getString(EXTRA_PKG);
+                if (mPinnedList.removePin(uri, pkg)) {
+                    handleSliceUnpinned(uri);
+                }
+                return null;
             }
-            addSpecs(b, specs);
-            return b;
-        } else if (method.equals(METHOD_GET_DESCENDANTS)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
-            mProvider.validateIncomingAuthority(uri.getAuthority());
-            Bundle b = new Bundle();
-            b.putParcelableArrayList(EXTRA_SLICE_DESCENDANTS,
-                    new ArrayList<>(handleGetDescendants(uri)));
-            return b;
-        } else if (method.equals(METHOD_CHECK_PERMISSION)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
-            mProvider.validateIncomingAuthority(uri.getAuthority());
-            int pid = extras.getInt(EXTRA_PID);
-            int uid = extras.getInt(EXTRA_UID);
-            Bundle b = new Bundle();
-            b.putInt(EXTRA_RESULT, mPermissionManager.checkSlicePermission(uri, pid, uid));
-            return b;
-        } else if (method.equals(METHOD_GRANT_PERMISSION)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
-            mProvider.validateIncomingAuthority(uri.getAuthority());
-            String toPkg = extras.getString(EXTRA_PKG);
-            if (Binder.getCallingUid() != Process.myUid()) {
-                throw new SecurityException("Only the owning process can manage slice permissions");
+            case METHOD_GET_PINNED_SPECS: {
+                Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+                mProvider.validateIncomingAuthority(uri.getAuthority());
+                Bundle b = new Bundle();
+                ArraySet<SliceSpec> specs = mPinnedList.getSpecs(uri);
+                if (specs.size() == 0) {
+                    throw new IllegalStateException(uri + " is not pinned");
+                }
+                addSpecs(b, specs);
+                return b;
             }
-            mPermissionManager.grantSlicePermission(uri, toPkg);
-        } else if (method.equals(METHOD_REVOKE_PERMISSION)) {
-            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
-            mProvider.validateIncomingAuthority(uri.getAuthority());
-            String toPkg = extras.getString(EXTRA_PKG);
-            if (Binder.getCallingUid() != Process.myUid()) {
-                throw new SecurityException("Only the owning process can manage slice permissions");
+            case METHOD_GET_DESCENDANTS: {
+                Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+                mProvider.validateIncomingAuthority(uri.getAuthority());
+                Bundle b = new Bundle();
+                b.putParcelableArrayList(EXTRA_SLICE_DESCENDANTS,
+                        new ArrayList<>(handleGetDescendants(uri)));
+                return b;
             }
-            mPermissionManager.revokeSlicePermission(uri, toPkg);
+            case METHOD_CHECK_PERMISSION: {
+                Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+                mProvider.validateIncomingAuthority(uri.getAuthority());
+                int pid = extras.getInt(EXTRA_PID);
+                int uid = extras.getInt(EXTRA_UID);
+                Bundle b = new Bundle();
+                b.putInt(EXTRA_RESULT, mPermissionManager.checkSlicePermission(uri, pid, uid));
+                return b;
+            }
+            case METHOD_GRANT_PERMISSION: {
+                Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+                mProvider.validateIncomingAuthority(uri.getAuthority());
+                String toPkg = extras.getString(EXTRA_PKG);
+                if (Binder.getCallingUid() != Process.myUid()) {
+                    throw new SecurityException(
+                            "Only the owning process can manage slice permissions");
+                }
+                mPermissionManager.grantSlicePermission(uri, toPkg);
+                break;
+            }
+            case METHOD_REVOKE_PERMISSION: {
+                Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+                mProvider.validateIncomingAuthority(uri.getAuthority());
+                String toPkg = extras.getString(EXTRA_PKG);
+                if (Binder.getCallingUid() != Process.myUid()) {
+                    throw new SecurityException(
+                            "Only the owning process can manage slice permissions");
+                }
+                mPermissionManager.revokeSlicePermission(uri, toPkg);
+                break;
+            }
         }
         return null;
     }
@@ -378,7 +390,6 @@
      * Compat version of {@link Slice#bindSlice}.
      */
     @Nullable
-    @SuppressWarnings("deprecation")
     public static Slice bindSlice(@NonNull Context context, @NonNull Intent intent,
             @NonNull Set<SliceSpec> supportedSpecs) {
         Preconditions.checkNotNull(intent, "intent");
@@ -435,23 +446,19 @@
     }
 
     @SuppressLint("WrongConstant") // Needed for IconCompat.TYPE_RESOURCE lint failure
-    @SuppressWarnings("deprecation")
     private static Slice parseSlice(final Context context, Bundle res) {
         if (res == null) {
             return null;
         }
         synchronized (SliceItemHolder.sSerializeLock) {
             try {
-                SliceItemHolder.sHandler = new SliceItemHolder.HolderHandler() {
-                    @Override
-                    public void handle(SliceItemHolder holder, String format) {
-                        if (holder.mVersionedParcelable instanceof IconCompat) {
-                            IconCompat icon = (IconCompat) holder.mVersionedParcelable;
-                            icon.checkResource(context);
-                            if (icon.getType() == IconCompat.TYPE_RESOURCE
-                                    && icon.getResId() == 0) {
-                                holder.mVersionedParcelable = null;
-                            }
+                SliceItemHolder.sHandler = (holder, format) -> {
+                    if (holder.mVersionedParcelable instanceof IconCompat) {
+                        IconCompat icon = (IconCompat) holder.mVersionedParcelable;
+                        icon.checkResource(context);
+                        if (icon.getType() == IconCompat.TYPE_RESOURCE
+                                && icon.getResId() == 0) {
+                            holder.mVersionedParcelable = null;
                         }
                     }
                 };
@@ -543,7 +550,6 @@
      * Compat version of {@link android.app.slice.SliceManager#mapIntentToUri}.
      */
     @Nullable
-    @SuppressWarnings("deprecation")
     public static Uri mapIntentToUri(@NonNull Context context, @NonNull Intent intent) {
         Preconditions.checkNotNull(intent, "intent");
         Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
@@ -599,7 +605,7 @@
      * Compat version of {@link android.app.slice.SliceManager#getSliceDescendants(Uri)}
      */
     @NonNull
-    @SuppressWarnings({"MixedMutabilityReturnType", "deprecation"})
+    @SuppressWarnings("MixedMutabilityReturnType")
     public static Collection<Uri> getSliceDescendants(@NonNull Context context, @NonNull Uri uri) {
         ContentResolver resolver = context.getContentResolver();
         try (ProviderHolder holder = acquireClient(resolver, uri)) {
@@ -685,7 +691,7 @@
     public static List<Uri> getPinnedSlices(@NonNull Context context) {
         ArrayList<Uri> pinnedSlices = new ArrayList<>();
         SharedPreferences prefs = context.getSharedPreferences(ALL_FILES, 0);
-        Set<String> prefSet = prefs.getStringSet(ALL_FILES, Collections.<String>emptySet());
+        Set<String> prefSet = prefs.getStringSet(ALL_FILES, Collections.emptySet());
         for (String pref : prefSet) {
             pinnedSlices.addAll(new CompatPinnedList(context, pref).getPinnedSlices());
         }
@@ -711,10 +717,22 @@
         public void close() {
             if (mProvider == null) return;
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-                mProvider.close();
+                Api24Impl.close(mProvider);
             } else {
                 mProvider.release();
             }
         }
+
+        @RequiresApi(24)
+        static class Api24Impl {
+            private Api24Impl() {
+                // This class is not instantiable.
+            }
+
+            @DoNotInline
+            static void close(ContentProviderClient contentProviderClient) {
+                contentProviderClient.close();
+            }
+        }
     }
 }
diff --git a/slice/slice-core/src/main/java/androidx/slice/core/SliceAction.java b/slice/slice-core/src/main/java/androidx/slice/core/SliceAction.java
index 843b1c8..6c47667 100644
--- a/slice/slice-core/src/main/java/androidx/slice/core/SliceAction.java
+++ b/slice/slice-core/src/main/java/androidx/slice/core/SliceAction.java
@@ -33,18 +33,20 @@
     /**
      * @param description the content description for this action.
      */
-    @Nullable
+    @NonNull
     SliceAction setContentDescription(@NonNull CharSequence description);
 
     /**
      * @param isChecked whether the state of this action is checked or not; only used for toggle
      *                  actions.
      */
+    @NonNull
     SliceAction setChecked(boolean isChecked);
 
     /**
      * Sets the priority of this action, with the lowest priority having the highest ranking.
      */
+    @NonNull
     SliceAction setPriority(@IntRange(from = 0) int priority);
 
     /**
diff --git a/slice/slice-core/src/main/java/androidx/slice/core/SliceActionImpl.java b/slice/slice-core/src/main/java/androidx/slice/core/SliceActionImpl.java
index 60ee23f..e46617b 100644
--- a/slice/slice-core/src/main/java/androidx/slice/core/SliceActionImpl.java
+++ b/slice/slice-core/src/main/java/androidx/slice/core/SliceActionImpl.java
@@ -54,6 +54,7 @@
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.graphics.drawable.IconCompat;
+import androidx.core.util.ObjectsCompat;
 import androidx.slice.Slice;
 import androidx.slice.SliceItem;
 
@@ -65,17 +66,29 @@
 @RequiresApi(19)
 public class SliceActionImpl implements SliceAction {
 
+    // Either mAction or mActionItem must be non-null.
+    @Nullable
     private PendingIntent mAction;
+
+    // Either mAction or mActionItem must be non-null.
+    @Nullable
+    private SliceItem mActionItem;
+
     private IconCompat mIcon;
     private int mImageMode = UNKNOWN_IMAGE;
     private CharSequence mTitle;
     private CharSequence mContentDescription;
+
+    @NonNull
     private ActionType mActionType = ActionType.DEFAULT;
+
     private boolean mIsChecked;
     private int mPriority = -1;
     private long mDateTimeMillis = -1;
+
+    @Nullable
     private SliceItem mSliceItem;
-    private SliceItem mActionItem;
+
     private String mActionKey;
     private boolean mIsActivity;
 
@@ -185,7 +198,7 @@
      */
     @RestrictTo(LIBRARY_GROUP)
     @SuppressLint("InlinedApi")
-    public SliceActionImpl(SliceItem slice) {
+    public SliceActionImpl(@NonNull SliceItem slice) {
         mSliceItem = slice;
         SliceItem actionItem = SliceQuery.find(slice, FORMAT_ACTION);
         if (actionItem == null) {
@@ -250,10 +263,11 @@
 
     /**
      * @param description the content description for this action.
+     * @return
      */
     @Nullable
     @Override
-    public SliceActionImpl setContentDescription(@NonNull CharSequence description) {
+    public @NonNull SliceAction setContentDescription(@NonNull CharSequence description) {
         mContentDescription = description;
         return this;
     }
@@ -262,6 +276,7 @@
      * @param isChecked whether the state of this action is checked or not; only used for toggle
      *                  actions.
      */
+    @NonNull
     @Override
     public SliceActionImpl setChecked(boolean isChecked) {
         mIsChecked = isChecked;
@@ -271,6 +286,7 @@
     /**
      * Sets the priority of this action, with the lowest priority having the highest ranking.
      */
+    @NonNull
     @Override
     public SliceActionImpl setPriority(@IntRange(from = 0) int priority) {
         mPriority = priority;
@@ -290,6 +306,7 @@
     /**
      * @return the {@link PendingIntent} associated with this action.
      */
+    @SuppressWarnings("ConstantConditions") // Either mAction or mActionItem must be non-null
     @NonNull
     @Override
     public PendingIntent getAction() {
@@ -299,6 +316,7 @@
     /**
      * @hide
      */
+    @Nullable
     @RestrictTo(LIBRARY_GROUP_PREFIX)
     public SliceItem getActionItem() {
         return mActionItem;
@@ -402,6 +420,8 @@
      */
     @NonNull
     public Slice buildSlice(@NonNull Slice.Builder builder) {
+        ObjectsCompat.requireNonNull(mAction, "Action must be non-null");
+
         return builder.addHints(HINT_SHORTCUT)
                 .addAction(mAction, buildSliceContent(builder).build(), getSubtype())
                 .build();
@@ -418,6 +438,7 @@
 
     /**
      */
+    @NonNull
     private Slice.Builder buildSliceContent(@NonNull Slice.Builder builder) {
         Slice.Builder sb = new Slice.Builder(builder);
         if (mIcon != null) {
diff --git a/slice/slice-core/src/main/java/androidx/slice/core/SliceQuery.java b/slice/slice-core/src/main/java/androidx/slice/core/SliceQuery.java
index 1830104..684de91 100644
--- a/slice/slice-core/src/main/java/androidx/slice/core/SliceQuery.java
+++ b/slice/slice-core/src/main/java/androidx/slice/core/SliceQuery.java
@@ -22,6 +22,8 @@
 import android.net.Uri;
 import android.text.TextUtils;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.slice.Slice;
@@ -43,7 +45,7 @@
 
     /**
      */
-    public static boolean hasAnyHints(SliceItem item, String... hints) {
+    public static boolean hasAnyHints(@NonNull SliceItem item, @Nullable String... hints) {
         if (hints == null) return false;
         for (String hint : hints) {
             if (item.hasHint(hint)) {
@@ -55,7 +57,7 @@
 
     /**
      */
-    public static boolean hasHints(SliceItem item, String... hints) {
+    public static boolean hasHints(@NonNull SliceItem item, @Nullable String... hints) {
         if (hints == null) return true;
         for (String hint : hints) {
             if (!TextUtils.isEmpty(hint) && !item.hasHint(hint)) {
@@ -67,7 +69,8 @@
 
     /**
      */
-    public static boolean hasHints(Slice item, String... hints) {
+    @SuppressWarnings("unused")
+    public static boolean hasHints(@NonNull Slice item, @Nullable String... hints) {
         if (hints == null) return true;
         for (String hint : hints) {
             if (!TextUtils.isEmpty(hint) && !item.hasHint(hint)) {
@@ -79,7 +82,10 @@
 
     /**
      */
-    public static SliceItem findNotContaining(SliceItem container, List<SliceItem> list) {
+    @SuppressWarnings("unused")
+    @Nullable
+    public static SliceItem findNotContaining(@Nullable SliceItem container,
+            @NonNull List<SliceItem> list) {
         SliceItem ret = null;
         while (ret == null && list.size() != 0) {
             SliceItem remove = list.remove(0);
@@ -92,186 +98,174 @@
 
     /**
      */
-    private static boolean contains(SliceItem container, final SliceItem item) {
+    private static boolean contains(@Nullable SliceItem container, @Nullable final SliceItem item) {
         if (container == null || item == null) return false;
-        return findSliceItem(toQueue(container), new Filter<SliceItem>() {
-            @Override
-            public boolean filter(SliceItem s) {
-                return s == item;
-            }
-        }) != null;
+        return findSliceItem(toQueue(container), s -> s == item) != null;
     }
 
     /**
      */
-    public static List<SliceItem> findAll(SliceItem s, String format) {
+    @NonNull
+    public static List<SliceItem> findAll(@NonNull SliceItem s, @Nullable String format) {
         return findAll(s, format, (String[]) null, null);
     }
 
     /**
      */
-    public static List<SliceItem> findAll(Slice s, String format, String hints, String nonHints) {
+    @SuppressWarnings("unused")
+    @NonNull
+    public static List<SliceItem> findAll(@NonNull Slice s, @Nullable String format,
+            @Nullable String hints, @Nullable String nonHints) {
         return findAll(s, format, new String[]{ hints }, new String[]{ nonHints });
     }
 
     /**
      */
-    public static List<SliceItem> findAll(SliceItem s, String format, String hints,
-            String nonHints) {
+    @NonNull
+    public static List<SliceItem> findAll(@NonNull SliceItem s, @Nullable String format,
+            @Nullable String hints, @Nullable String nonHints) {
         return findAll(s, format, new String[]{ hints }, new String[]{ nonHints });
     }
 
     /**
      */
-    public static List<SliceItem> findAll(Slice s, final String format, final String[] hints,
-            final String[] nonHints) {
+    @NonNull
+    public static List<SliceItem> findAll(@NonNull Slice s, @Nullable final String format,
+            @Nullable final String[] hints, @Nullable final String[] nonHints) {
         ArrayList<SliceItem> ret = new ArrayList<>();
-        findAll(toQueue(s), new Filter<SliceItem>() {
-            @Override
-            public boolean filter(SliceItem item) {
-                return checkFormat(item, format)
-                        && (hasHints(item, hints) && !hasAnyHints(item, nonHints));
-            }
-        }, ret);
+        findAll(toQueue(s), item -> checkFormat(item, format)
+                && (hasHints(item, hints) && !hasAnyHints(item, nonHints)), ret);
         return ret;
     }
 
     /**
      */
-    public static List<SliceItem> findAll(SliceItem s, final String format, final String[] hints,
-            final String[] nonHints) {
+    @NonNull
+    public static List<SliceItem> findAll(@NonNull SliceItem s, @Nullable final String format,
+            @Nullable final String[] hints, @Nullable final String[] nonHints) {
         ArrayList<SliceItem> ret = new ArrayList<>();
-        findAll(toQueue(s), new Filter<SliceItem>() {
-            @Override
-            public boolean filter(SliceItem item) {
-                return checkFormat(item, format)
-                        && (hasHints(item, hints) && !hasAnyHints(item, nonHints));
-            }
-        }, ret);
+        findAll(toQueue(s), item -> checkFormat(item, format)
+                && (hasHints(item, hints) && !hasAnyHints(item, nonHints)), ret);
         return ret;
     }
 
     /**
      */
-    public static SliceItem find(Slice s, String format, String hints, String nonHints) {
+    @Nullable
+    public static SliceItem find(@Nullable Slice s, @Nullable String format, @Nullable String hints,
+            @Nullable String nonHints) {
         return find(s, format, new String[]{ hints }, new String[]{ nonHints });
     }
 
     /**
      */
-    public static SliceItem find(Slice s, String format) {
+    @Nullable
+    public static SliceItem find(@Nullable Slice s, @Nullable String format) {
         return find(s, format, (String[]) null, null);
     }
 
     /**
      */
-    public static SliceItem find(SliceItem s, String format) {
+    @Nullable
+    public static SliceItem find(@Nullable SliceItem s, @Nullable String format) {
         return find(s, format, (String[]) null, null);
     }
 
     /**
      */
-    public static SliceItem find(SliceItem s, String format, String hints, String nonHints) {
+    @Nullable
+    public static SliceItem find(@Nullable SliceItem s, @Nullable String format,
+            @Nullable String hints, @Nullable String nonHints) {
         return find(s, format, new String[]{ hints }, new String[]{ nonHints });
     }
 
     /**
      */
-    public static SliceItem find(Slice s, final String format, final String[] hints,
-            final String[] nonHints) {
+    @Nullable
+    public static SliceItem find(@Nullable Slice s, @Nullable final String format,
+            @Nullable final String[] hints, @Nullable final String[] nonHints) {
         if (s == null) return null;
-        return findSliceItem(toQueue(s), new Filter<SliceItem>() {
-            @Override
-            public boolean filter(SliceItem item) {
-                return checkFormat(item, format)
-                        && (hasHints(item, hints) && !hasAnyHints(item, nonHints));
-            }
-        });
+        return findSliceItem(toQueue(s), item -> checkFormat(item, format)
+                && (hasHints(item, hints) && !hasAnyHints(item, nonHints)));
     }
 
     /**
      */
-    public static SliceItem findSubtype(Slice s, final String format, final String subtype) {
+    @Nullable
+    public static SliceItem findSubtype(@Nullable Slice s, @Nullable final String format,
+            @Nullable final String subtype) {
         if (s == null) return null;
-        return findSliceItem(toQueue(s), new Filter<SliceItem>() {
-            @Override
-            public boolean filter(SliceItem item) {
-                return checkFormat(item, format) && checkSubtype(item, subtype);
-            }
-        });
+        return findSliceItem(toQueue(s),
+                item -> checkFormat(item, format) && checkSubtype(item, subtype));
     }
 
     /**
      */
-    public static SliceItem findSubtype(SliceItem s, final String format, final String subtype) {
+    @Nullable
+    public static SliceItem findSubtype(@Nullable SliceItem s, @Nullable final String format,
+            @Nullable final String subtype) {
         if (s == null) return null;
-        return findSliceItem(toQueue(s), new Filter<SliceItem>() {
-            @Override
-            public boolean filter(SliceItem item) {
-                return checkFormat(item, format) && checkSubtype(item, subtype);
-            }
-        });
+        return findSliceItem(toQueue(s),
+                item -> checkFormat(item, format) && checkSubtype(item, subtype));
     }
 
     /**
      */
-    public static SliceItem find(SliceItem s, final String format, final String[] hints,
-            final String[] nonHints) {
+    @Nullable
+    public static SliceItem find(@Nullable SliceItem s, @Nullable final String format,
+            @Nullable final String[] hints, @Nullable final String[] nonHints) {
         if (s == null) return null;
-        return findSliceItem(toQueue(s), new Filter<SliceItem>() {
-            @Override
-            public boolean filter(SliceItem item) {
-                return checkFormat(item, format)
-                        && (hasHints(item, hints) && !hasAnyHints(item, nonHints));
-            }
-        });
+        return findSliceItem(toQueue(s), item -> checkFormat(item, format)
+                && (hasHints(item, hints) && !hasAnyHints(item, nonHints)));
     }
 
     @SuppressWarnings("WeakerAccess") /* synthetic access */
-    static boolean checkFormat(SliceItem item, String format) {
+    static boolean checkFormat(@NonNull SliceItem item, @Nullable String format) {
         return format == null || format.equals(item.getFormat());
     }
 
     @SuppressWarnings("WeakerAccess") /* synthetic access */
-    static boolean checkSubtype(SliceItem item, String subtype) {
+    static boolean checkSubtype(@NonNull SliceItem item, @Nullable String subtype) {
         return subtype == null || subtype.equals(item.getSubType());
     }
 
-    private static Deque<SliceItem> toQueue(Slice item) {
+    private static @NonNull Deque<SliceItem> toQueue(@NonNull Slice item) {
         Deque<SliceItem> q = new ArrayDeque<>();
         Collections.addAll(q, item.getItemArray());
         return q;
     }
 
-    private static Deque<SliceItem> toQueue(SliceItem item) {
+    private static @NonNull Deque<SliceItem> toQueue(@NonNull SliceItem item) {
         Deque<SliceItem> q = new ArrayDeque<>();
         q.add(item);
         return q;
     }
 
-    private static SliceItem findSliceItem(final Deque<SliceItem> items, Filter<SliceItem> f) {
+    @Nullable
+    private static SliceItem findSliceItem(@NonNull final Deque<SliceItem> items,
+            @NonNull Filter<SliceItem> f) {
         while (!items.isEmpty()) {
             SliceItem item = items.poll();
             if (f.filter(item)) {
                 return item;
             }
-            if (FORMAT_SLICE.equals(item.getFormat())
-                    || FORMAT_ACTION.equals(item.getFormat())) {
+            if (item != null && (FORMAT_SLICE.equals(item.getFormat())
+                    || FORMAT_ACTION.equals(item.getFormat()))) {
                 Collections.addAll(items, item.getSlice().getItemArray());
             }
         }
         return null;
     }
 
-    private static void findAll(final Deque<SliceItem> items, Filter<SliceItem> f,
-            List<SliceItem> out) {
+    private static void findAll(@NonNull final Deque<SliceItem> items,
+            @NonNull Filter<SliceItem> f, @NonNull List<SliceItem> out) {
         while (!items.isEmpty()) {
             SliceItem item = items.poll();
             if (f.filter(item)) {
                 out.add(item);
             }
-            if (FORMAT_SLICE.equals(item.getFormat())
-                    || FORMAT_ACTION.equals(item.getFormat())) {
+            if (item != null && (FORMAT_SLICE.equals(item.getFormat())
+                    || FORMAT_ACTION.equals(item.getFormat()))) {
                 Collections.addAll(items, item.getSlice().getItemArray());
             }
         }
@@ -280,11 +274,12 @@
     /**
      * Finds an item matching provided params that is a direct child of the slice.
      */
-    public static SliceItem findTopLevelItem(Slice s, final String format, final String subtype,
-            final String[] hints, final String[] nonHints) {
+    @Nullable
+    public static SliceItem findTopLevelItem(@NonNull Slice s, @Nullable final String format,
+            @Nullable final String subtype, @Nullable final String[] hints,
+            @Nullable final String[] nonHints) {
         SliceItem[] items = s.getItemArray();
-        for (int i = 0; i < items.length; i++) {
-            SliceItem item = items[i];
+        for (SliceItem item : items) {
             if (checkFormat(item, format)
                     && checkSubtype(item, subtype)
                     && hasHints(item, hints)
@@ -296,19 +291,15 @@
     }
 
     /**
-     * @hide
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
-    public static SliceItem findItem(Slice s, final Uri uri) {
-        return findSliceItem(toQueue(s), new Filter<SliceItem>() {
-            @Override
-            public boolean filter(SliceItem input) {
-                if (FORMAT_ACTION.equals(input.getFormat()) || FORMAT_SLICE.equals(
-                        input.getFormat())) {
-                    return uri.equals(input.getSlice().getUri());
-                }
-                return false;
+    @Nullable
+    public static SliceItem findItem(@NonNull Slice s, @NonNull final Uri uri) {
+        return findSliceItem(toQueue(s), input -> {
+            if (FORMAT_ACTION.equals(input.getFormat()) || FORMAT_SLICE.equals(
+                    input.getFormat())) {
+                return uri.equals(input.getSlice().getUri());
             }
+            return false;
         });
     }
 
diff --git a/slice/slice-test/lint-baseline.xml b/slice/slice-test/lint-baseline.xml
index 12eb9fd..a2616bf 100644
--- a/slice/slice-test/lint-baseline.xml
+++ b/slice/slice-test/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
diff --git a/slice/slice-view/lint-baseline.xml b/slice/slice-view/lint-baseline.xml
index fbdf589..fc94cc9 100644
--- a/slice/slice-view/lint-baseline.xml
+++ b/slice/slice-view/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="BanSynchronizedMethods"
@@ -75,7 +75,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;abc_slice_duration_min&quot; formatted=&quot;false&quot; msgid=&quot;7664017844210142826&quot;>"
         errorLine2="    ^">
         <location
@@ -84,7 +84,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;abc_slice_duration_min&quot; formatted=&quot;false&quot; msgid=&quot;7664017844210142826&quot;>"
         errorLine2="    ^">
         <location
@@ -93,7 +93,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;abc_slice_duration_years&quot; formatted=&quot;false&quot; msgid=&quot;2628491538787454021&quot;>"
         errorLine2="    ^">
         <location
@@ -102,7 +102,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;abc_slice_duration_years&quot; formatted=&quot;false&quot; msgid=&quot;2628491538787454021&quot;>"
         errorLine2="    ^">
         <location
@@ -111,7 +111,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;abc_slice_duration_days&quot; formatted=&quot;false&quot; msgid=&quot;8356547162075064530&quot;>"
         errorLine2="    ^">
         <location
@@ -120,7 +120,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;abc_slice_duration_days&quot; formatted=&quot;false&quot; msgid=&quot;8356547162075064530&quot;>"
         errorLine2="    ^">
         <location
diff --git a/slice/slice-view/src/main/java/androidx/slice/SliceUtils.java b/slice/slice-view/src/main/java/androidx/slice/SliceUtils.java
index 5dfdf5c..cf42a848 100644
--- a/slice/slice-view/src/main/java/androidx/slice/SliceUtils.java
+++ b/slice/slice-view/src/main/java/androidx/slice/SliceUtils.java
@@ -40,6 +40,7 @@
 
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.graphics.drawable.IconCompat;
@@ -188,12 +189,8 @@
             @NonNull OutputStream output,
             @NonNull final SerializeOptions options) throws IllegalArgumentException {
         synchronized (SliceItemHolder.sSerializeLock) {
-            SliceItemHolder.sHandler = new SliceItemHolder.HolderHandler() {
-                @Override
-                public void handle(SliceItemHolder holder, String format) {
-                    handleOptions(context, holder, format, options);
-                }
-            };
+            SliceItemHolder.sHandler =
+                    (holder, format) -> handleOptions(context, holder, format, options);
             ParcelUtils.toOutputStream(s, output);
             SliceItemHolder.sHandler = null;
         }
@@ -277,14 +274,15 @@
             Slice slice;
             final SliceItem.ActionHandler handler = new SliceItem.ActionHandler() {
                 @Override
-                public void onAction(SliceItem item, Context context, Intent intent) {
+                public void onAction(@NonNull SliceItem item, @Nullable Context context,
+                        Intent intent) {
                     listener.onSliceAction(item.getSlice().getUri(), context, intent);
                 }
             };
             synchronized (SliceItemHolder.sSerializeLock) {
                 SliceItemHolder.sHandler = new SliceItemHolder.HolderHandler() {
                     @Override
-                    public void handle(SliceItemHolder holder, String format) {
+                    public void handle(@NonNull SliceItemHolder holder, @NonNull String format) {
                         setActionsAndUpdateIcons(holder, handler, context, format);
                     }
                 };
diff --git a/slice/slice-view/src/main/java/androidx/slice/SliceXml.java b/slice/slice-view/src/main/java/androidx/slice/SliceXml.java
index 3c085d6..aa8b562 100644
--- a/slice/slice-view/src/main/java/androidx/slice/SliceXml.java
+++ b/slice/slice-view/src/main/java/androidx/slice/SliceXml.java
@@ -37,6 +37,8 @@
 import android.text.TextUtils;
 import android.util.Base64;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.graphics.drawable.IconCompat;
@@ -207,7 +209,8 @@
                 b.addAction(parseSlice(context, parser, listener), subtype,
                         new SliceItem.ActionHandler() {
                             @Override
-                            public void onAction(SliceItem item, Context context, Intent intent) {
+                            public void onAction(@NonNull SliceItem item, @Nullable Context context,
+                                    Intent intent) {
                                 listener.onSliceAction(item.getSlice().getUri(), context, intent);
                             }
                         });
diff --git a/sqlite/sqlite-framework/lint-baseline.xml b/sqlite/sqlite-framework/lint-baseline.xml
index 5b3e294..985b8ee 100644
--- a/sqlite/sqlite-framework/lint-baseline.xml
+++ b/sqlite/sqlite-framework/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha08)" variant="all" version="7.3.0-alpha08">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/sqlite/sqlite-framework/src/androidTest/java/androidx/sqlite/db/framework/OpenHelperRecoveryTest.kt b/sqlite/sqlite-framework/src/androidTest/java/androidx/sqlite/db/framework/OpenHelperRecoveryTest.kt
index 2ff6161..eca7a3b 100644
--- a/sqlite/sqlite-framework/src/androidTest/java/androidx/sqlite/db/framework/OpenHelperRecoveryTest.kt
+++ b/sqlite/sqlite-framework/src/androidTest/java/androidx/sqlite/db/framework/OpenHelperRecoveryTest.kt
@@ -108,9 +108,8 @@
     @Test
     fun allowDataLossOnRecovery_onUpgradeError() {
         // Create DB at version 1, open and close it
-        FrameworkSQLiteOpenHelper(context, dbName, EmptyCallback(1), false, true).let {
-            it.writableDatabase.close()
-        }
+        FrameworkSQLiteOpenHelper(context, dbName, EmptyCallback(1), false, true)
+            .writableDatabase.close()
 
         // A callback to open DB at version 2, it has a bad migration.
         val badCallback = object : SupportSQLiteOpenHelper.Callback(2) {
diff --git a/sqlite/sqlite-framework/src/main/java/androidx/sqlite/db/framework/FrameworkSQLiteDatabase.java b/sqlite/sqlite-framework/src/main/java/androidx/sqlite/db/framework/FrameworkSQLiteDatabase.java
index 7e14997..a07a5c7 100644
--- a/sqlite/sqlite-framework/src/main/java/androidx/sqlite/db/framework/FrameworkSQLiteDatabase.java
+++ b/sqlite/sqlite-framework/src/main/java/androidx/sqlite/db/framework/FrameworkSQLiteDatabase.java
@@ -22,14 +22,13 @@
 import android.database.Cursor;
 import android.database.SQLException;
 import android.database.sqlite.SQLiteCursor;
-import android.database.sqlite.SQLiteCursorDriver;
 import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteQuery;
 import android.database.sqlite.SQLiteTransactionListener;
 import android.os.Build;
 import android.os.CancellationSignal;
 import android.util.Pair;
 
+import androidx.annotation.DoNotInline;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
@@ -63,8 +62,9 @@
         mDelegate = delegate;
     }
 
+    @NonNull
     @Override
-    public SupportSQLiteStatement compileStatement(String sql) {
+    public SupportSQLiteStatement compileStatement(@NonNull String sql) {
         return new FrameworkSQLiteStatement(mDelegate.compileStatement(sql));
     }
 
@@ -79,13 +79,14 @@
     }
 
     @Override
-    public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
+    public void beginTransactionWithListener(
+            @NonNull SQLiteTransactionListener transactionListener) {
         mDelegate.beginTransactionWithListener(transactionListener);
     }
 
     @Override
     public void beginTransactionWithListenerNonExclusive(
-            SQLiteTransactionListener transactionListener) {
+            @NonNull SQLiteTransactionListener transactionListener) {
         mDelegate.beginTransactionWithListenerNonExclusive(transactionListener);
     }
 
@@ -124,13 +125,10 @@
         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
     }
 
-    // Adding @RequiresApi(30) would prevent unbundled implementations from offering this
-    // functionality to lower API levels.
-    @SuppressWarnings("ClassVerificationFailure")
     @Override
     public void execPerConnectionSQL(@NonNull String sql, @Nullable Object[] bindArgs) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
-            mDelegate.execPerConnectionSQL(sql, bindArgs);
+            Api30Impl.execPerConnectionSQL(mDelegate, sql, bindArgs);
         } else {
             throw new UnsupportedOperationException("execPerConnectionSQL is not supported on a "
                     + "SDK version lower than 30, current version is: " + Build.VERSION.SDK_INT);
@@ -168,52 +166,44 @@
     }
 
     @Override
-    public Cursor query(String query) {
+    public @NonNull Cursor query(@NonNull String query) {
         return query(new SimpleSQLiteQuery(query));
     }
 
     @Override
-    public Cursor query(String query, Object[] bindArgs) {
+    public @NonNull Cursor query(@NonNull String query, @NonNull Object[] bindArgs) {
         return query(new SimpleSQLiteQuery(query, bindArgs));
     }
 
-
     @Override
-    public Cursor query(final SupportSQLiteQuery supportQuery) {
-        return mDelegate.rawQueryWithFactory(new SQLiteDatabase.CursorFactory() {
-            @Override
-            public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery,
-                    String editTable, SQLiteQuery query) {
-                supportQuery.bindTo(new FrameworkSQLiteProgram(query));
-                return new SQLiteCursor(masterQuery, editTable, query);
-            }
+    public @NonNull Cursor query(@NonNull final SupportSQLiteQuery supportQuery) {
+        return mDelegate.rawQueryWithFactory((db, masterQuery, editTable, query) -> {
+            supportQuery.bindTo(new FrameworkSQLiteProgram(query));
+            return new SQLiteCursor(masterQuery, editTable, query);
         }, supportQuery.getSql(), EMPTY_STRING_ARRAY, null);
     }
 
     @Override
-    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
-    public Cursor query(final SupportSQLiteQuery supportQuery,
+    @RequiresApi(16)
+    public @NonNull Cursor query(@NonNull final SupportSQLiteQuery supportQuery,
             CancellationSignal cancellationSignal) {
         return SupportSQLiteCompat.Api16Impl.rawQueryWithFactory(mDelegate, supportQuery.getSql(),
-                EMPTY_STRING_ARRAY, null, cancellationSignal, new SQLiteDatabase.CursorFactory() {
-                    @Override
-                    public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery,
-                            String editTable, SQLiteQuery query) {
-                        supportQuery.bindTo(new FrameworkSQLiteProgram(query));
-                        return new SQLiteCursor(masterQuery, editTable, query);
-                    }
+                EMPTY_STRING_ARRAY, null, cancellationSignal,
+                (db, masterQuery, editTable, query) -> {
+                    supportQuery.bindTo(new FrameworkSQLiteProgram(query));
+                    return new SQLiteCursor(masterQuery, editTable, query);
                 });
     }
 
     @Override
-    public long insert(String table, int conflictAlgorithm, ContentValues values)
+    public long insert(@NonNull String table, int conflictAlgorithm, @NonNull ContentValues values)
             throws SQLException {
         return mDelegate.insertWithOnConflict(table, null, values,
                 conflictAlgorithm);
     }
 
     @Override
-    public int delete(String table, String whereClause, Object[] whereArgs) {
+    public int delete(@NonNull String table, String whereClause, Object[] whereArgs) {
         String query = "DELETE FROM " + table
                 + (isEmpty(whereClause) ? "" : " WHERE " + whereClause);
         SupportSQLiteStatement statement = compileStatement(query);
@@ -223,8 +213,8 @@
 
 
     @Override
-    public int update(String table, int conflictAlgorithm, ContentValues values, String whereClause,
-            Object[] whereArgs) {
+    public int update(@NonNull String table, int conflictAlgorithm, ContentValues values,
+            String whereClause, Object[] whereArgs) {
         // taken from SQLiteDatabase class.
         if (values == null || values.size() == 0) {
             throw new IllegalArgumentException("Empty values");
@@ -261,12 +251,12 @@
     }
 
     @Override
-    public void execSQL(String sql) throws SQLException {
+    public void execSQL(@NonNull String sql) throws SQLException {
         mDelegate.execSQL(sql);
     }
 
     @Override
-    public void execSQL(String sql, Object[] bindArgs) throws SQLException {
+    public void execSQL(@NonNull String sql, Object[] bindArgs) throws SQLException {
         mDelegate.execSQL(sql, bindArgs);
     }
 
@@ -291,7 +281,7 @@
     }
 
     @Override
-    public void setLocale(Locale locale) {
+    public void setLocale(@NonNull Locale locale) {
         mDelegate.setLocale(locale);
     }
 
@@ -344,4 +334,17 @@
     boolean isDelegate(SQLiteDatabase sqLiteDatabase) {
         return mDelegate == sqLiteDatabase;
     }
+
+    @RequiresApi(30)
+    static class Api30Impl {
+        private Api30Impl() {
+            // This class is not instantiable.
+        }
+
+        @DoNotInline
+        static void execPerConnectionSQL(SQLiteDatabase sQLiteDatabase, String sql,
+                Object[] bindArgs) {
+            sQLiteDatabase.execPerConnectionSQL(sql, bindArgs);
+        }
+    }
 }
diff --git a/sqlite/sqlite-framework/src/main/java/androidx/sqlite/db/framework/FrameworkSQLiteProgram.java b/sqlite/sqlite-framework/src/main/java/androidx/sqlite/db/framework/FrameworkSQLiteProgram.java
index d352d56..051a625 100644
--- a/sqlite/sqlite-framework/src/main/java/androidx/sqlite/db/framework/FrameworkSQLiteProgram.java
+++ b/sqlite/sqlite-framework/src/main/java/androidx/sqlite/db/framework/FrameworkSQLiteProgram.java
@@ -18,6 +18,7 @@
 
 import android.database.sqlite.SQLiteProgram;
 
+import androidx.annotation.NonNull;
 import androidx.sqlite.db.SupportSQLiteProgram;
 
 /**
@@ -46,12 +47,12 @@
     }
 
     @Override
-    public void bindString(int index, String value) {
+    public void bindString(int index, @NonNull String value) {
         mDelegate.bindString(index, value);
     }
 
     @Override
-    public void bindBlob(int index, byte[] value) {
+    public void bindBlob(int index, @NonNull byte[] value) {
         mDelegate.bindBlob(index, value);
     }
 
diff --git a/sqlite/sqlite-inspection/lint-baseline.xml b/sqlite/sqlite-inspection/lint-baseline.xml
index 14684a0..7c3078b 100644
--- a/sqlite/sqlite-inspection/lint-baseline.xml
+++ b/sqlite/sqlite-inspection/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="BanUncheckedReflection"
diff --git a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/RoomInvalidationRegistry.java b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/RoomInvalidationRegistry.java
index 86fc8b7..44def67 100644
--- a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/RoomInvalidationRegistry.java
+++ b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/RoomInvalidationRegistry.java
@@ -16,6 +16,7 @@
 
 package androidx.sqlite.inspection;
 
+import android.annotation.SuppressLint;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -138,6 +139,7 @@
             }
         }
 
+        @SuppressLint("BanUncheckedReflection") // Not a platform method.
         public void trigger(Object instance) {
             if (mRefreshMethod != null) {
                 try {
diff --git a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqlDelightInvalidation.java b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqlDelightInvalidation.java
index bea42ad..cca016b 100644
--- a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqlDelightInvalidation.java
+++ b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqlDelightInvalidation.java
@@ -16,12 +16,15 @@
 
 package androidx.sqlite.inspection;
 
+import android.annotation.SuppressLint;
+
 import androidx.annotation.NonNull;
 import androidx.inspection.InspectorEnvironment;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.List;
+import java.util.Objects;
 
 class SqlDelightInvalidation {
     private static final String SQLDELIGHT_QUERY_CLASS_NAME = "com.squareup.sqldelight.Query";
@@ -41,6 +44,7 @@
     @NonNull
     static SqlDelightInvalidation create(@NonNull InspectorEnvironment environment) {
         ClassLoader classLoader = SqlDelightInvalidation.class.getClassLoader();
+        Objects.requireNonNull(classLoader);
         try {
             Class<?> queryClass = classLoader.loadClass(SQLDELIGHT_QUERY_CLASS_NAME);
             Method notifyMethod = queryClass.getMethod(SQLDELIGHT_NOTIFY_METHOD_NAME);
@@ -61,6 +65,7 @@
         }
     }
 
+    @SuppressLint("BanUncheckedReflection") // Not a platform method.
     private void notifyDataChanged(Object query) {
         try {
             mNotifyDataChangeMethod.invoke(query);
diff --git a/sqlite/sqlite/api/current.txt b/sqlite/sqlite/api/current.txt
index 927cb1b..1014417 100644
--- a/sqlite/sqlite/api/current.txt
+++ b/sqlite/sqlite/api/current.txt
@@ -2,34 +2,34 @@
 package androidx.sqlite.db {
 
   public final class SimpleSQLiteQuery implements androidx.sqlite.db.SupportSQLiteQuery {
-    ctor public SimpleSQLiteQuery(String!, Object![]?);
-    ctor public SimpleSQLiteQuery(String!);
-    method public static void bind(androidx.sqlite.db.SupportSQLiteProgram!, Object![]!);
-    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram!);
+    ctor public SimpleSQLiteQuery(String, Object![]?);
+    ctor public SimpleSQLiteQuery(String);
+    method public static void bind(androidx.sqlite.db.SupportSQLiteProgram, Object![]?);
+    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram);
     method public int getArgCount();
-    method public String! getSql();
+    method public String getSql();
   }
 
   public interface SupportSQLiteDatabase extends java.io.Closeable {
     method public void beginTransaction();
     method public void beginTransactionNonExclusive();
-    method public void beginTransactionWithListener(android.database.sqlite.SQLiteTransactionListener!);
-    method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener!);
-    method public androidx.sqlite.db.SupportSQLiteStatement! compileStatement(String!);
-    method public int delete(String!, String!, Object![]!);
+    method public void beginTransactionWithListener(android.database.sqlite.SQLiteTransactionListener);
+    method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
+    method public androidx.sqlite.db.SupportSQLiteStatement compileStatement(String);
+    method public int delete(String, String?, Object![]?);
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public void disableWriteAheadLogging();
     method public boolean enableWriteAheadLogging();
     method public void endTransaction();
     method public default void execPerConnectionSQL(String, Object![]?);
-    method public void execSQL(String!) throws android.database.SQLException;
-    method public void execSQL(String!, Object![]!) throws android.database.SQLException;
-    method public java.util.List<android.util.Pair<java.lang.String!,java.lang.String!>!>! getAttachedDbs();
+    method public void execSQL(String) throws android.database.SQLException;
+    method public void execSQL(String, Object![]) throws android.database.SQLException;
+    method public java.util.List<android.util.Pair<java.lang.String!,java.lang.String!>!>? getAttachedDbs();
     method public long getMaximumSize();
     method public long getPageSize();
-    method public String! getPath();
+    method public String? getPath();
     method public int getVersion();
     method public boolean inTransaction();
-    method public long insert(String!, int, android.content.ContentValues!) throws android.database.SQLException;
+    method public long insert(String, int, android.content.ContentValues) throws android.database.SQLException;
     method public boolean isDatabaseIntegrityOk();
     method public boolean isDbLockedByCurrentThread();
     method public default boolean isExecPerConnectionSQLSupported();
@@ -37,18 +37,18 @@
     method public boolean isReadOnly();
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public boolean isWriteAheadLoggingEnabled();
     method public boolean needUpgrade(int);
-    method public android.database.Cursor! query(String!);
-    method public android.database.Cursor! query(String!, Object![]!);
-    method public android.database.Cursor! query(androidx.sqlite.db.SupportSQLiteQuery!);
-    method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public android.database.Cursor! query(androidx.sqlite.db.SupportSQLiteQuery!, android.os.CancellationSignal!);
+    method public android.database.Cursor query(String);
+    method public android.database.Cursor query(String, Object![]);
+    method public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery);
+    method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery, android.os.CancellationSignal?);
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public void setForeignKeyConstraintsEnabled(boolean);
-    method public void setLocale(java.util.Locale!);
+    method public void setLocale(java.util.Locale);
     method public void setMaxSqlCacheSize(int);
     method public long setMaximumSize(long);
     method public void setPageSize(long);
     method public void setTransactionSuccessful();
     method public void setVersion(int);
-    method public int update(String!, int, android.content.ContentValues!, String!, Object![]!);
+    method public int update(String, int, android.content.ContentValues, String?, Object![]?);
     method public boolean yieldIfContendedSafely();
     method public boolean yieldIfContendedSafely(long);
   }
@@ -56,8 +56,8 @@
   public interface SupportSQLiteOpenHelper extends java.io.Closeable {
     method public void close();
     method public String? getDatabaseName();
-    method public androidx.sqlite.db.SupportSQLiteDatabase! getReadableDatabase();
-    method public androidx.sqlite.db.SupportSQLiteDatabase! getWritableDatabase();
+    method public androidx.sqlite.db.SupportSQLiteDatabase getReadableDatabase();
+    method public androidx.sqlite.db.SupportSQLiteDatabase getWritableDatabase();
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public void setWriteAheadLoggingEnabled(boolean);
   }
 
@@ -94,18 +94,18 @@
   }
 
   public interface SupportSQLiteProgram extends java.io.Closeable {
-    method public void bindBlob(int, byte[]!);
+    method public void bindBlob(int, byte[]);
     method public void bindDouble(int, double);
     method public void bindLong(int, long);
     method public void bindNull(int);
-    method public void bindString(int, String!);
+    method public void bindString(int, String);
     method public void clearBindings();
   }
 
   public interface SupportSQLiteQuery {
-    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram!);
+    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram);
     method public int getArgCount();
-    method public String! getSql();
+    method public String getSql();
   }
 
   public final class SupportSQLiteQueryBuilder {
@@ -125,7 +125,7 @@
     method public long executeInsert();
     method public int executeUpdateDelete();
     method public long simpleQueryForLong();
-    method public String! simpleQueryForString();
+    method public String? simpleQueryForString();
   }
 
 }
diff --git a/sqlite/sqlite/api/public_plus_experimental_current.txt b/sqlite/sqlite/api/public_plus_experimental_current.txt
index 927cb1b..1014417 100644
--- a/sqlite/sqlite/api/public_plus_experimental_current.txt
+++ b/sqlite/sqlite/api/public_plus_experimental_current.txt
@@ -2,34 +2,34 @@
 package androidx.sqlite.db {
 
   public final class SimpleSQLiteQuery implements androidx.sqlite.db.SupportSQLiteQuery {
-    ctor public SimpleSQLiteQuery(String!, Object![]?);
-    ctor public SimpleSQLiteQuery(String!);
-    method public static void bind(androidx.sqlite.db.SupportSQLiteProgram!, Object![]!);
-    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram!);
+    ctor public SimpleSQLiteQuery(String, Object![]?);
+    ctor public SimpleSQLiteQuery(String);
+    method public static void bind(androidx.sqlite.db.SupportSQLiteProgram, Object![]?);
+    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram);
     method public int getArgCount();
-    method public String! getSql();
+    method public String getSql();
   }
 
   public interface SupportSQLiteDatabase extends java.io.Closeable {
     method public void beginTransaction();
     method public void beginTransactionNonExclusive();
-    method public void beginTransactionWithListener(android.database.sqlite.SQLiteTransactionListener!);
-    method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener!);
-    method public androidx.sqlite.db.SupportSQLiteStatement! compileStatement(String!);
-    method public int delete(String!, String!, Object![]!);
+    method public void beginTransactionWithListener(android.database.sqlite.SQLiteTransactionListener);
+    method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
+    method public androidx.sqlite.db.SupportSQLiteStatement compileStatement(String);
+    method public int delete(String, String?, Object![]?);
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public void disableWriteAheadLogging();
     method public boolean enableWriteAheadLogging();
     method public void endTransaction();
     method public default void execPerConnectionSQL(String, Object![]?);
-    method public void execSQL(String!) throws android.database.SQLException;
-    method public void execSQL(String!, Object![]!) throws android.database.SQLException;
-    method public java.util.List<android.util.Pair<java.lang.String!,java.lang.String!>!>! getAttachedDbs();
+    method public void execSQL(String) throws android.database.SQLException;
+    method public void execSQL(String, Object![]) throws android.database.SQLException;
+    method public java.util.List<android.util.Pair<java.lang.String!,java.lang.String!>!>? getAttachedDbs();
     method public long getMaximumSize();
     method public long getPageSize();
-    method public String! getPath();
+    method public String? getPath();
     method public int getVersion();
     method public boolean inTransaction();
-    method public long insert(String!, int, android.content.ContentValues!) throws android.database.SQLException;
+    method public long insert(String, int, android.content.ContentValues) throws android.database.SQLException;
     method public boolean isDatabaseIntegrityOk();
     method public boolean isDbLockedByCurrentThread();
     method public default boolean isExecPerConnectionSQLSupported();
@@ -37,18 +37,18 @@
     method public boolean isReadOnly();
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public boolean isWriteAheadLoggingEnabled();
     method public boolean needUpgrade(int);
-    method public android.database.Cursor! query(String!);
-    method public android.database.Cursor! query(String!, Object![]!);
-    method public android.database.Cursor! query(androidx.sqlite.db.SupportSQLiteQuery!);
-    method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public android.database.Cursor! query(androidx.sqlite.db.SupportSQLiteQuery!, android.os.CancellationSignal!);
+    method public android.database.Cursor query(String);
+    method public android.database.Cursor query(String, Object![]);
+    method public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery);
+    method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery, android.os.CancellationSignal?);
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public void setForeignKeyConstraintsEnabled(boolean);
-    method public void setLocale(java.util.Locale!);
+    method public void setLocale(java.util.Locale);
     method public void setMaxSqlCacheSize(int);
     method public long setMaximumSize(long);
     method public void setPageSize(long);
     method public void setTransactionSuccessful();
     method public void setVersion(int);
-    method public int update(String!, int, android.content.ContentValues!, String!, Object![]!);
+    method public int update(String, int, android.content.ContentValues, String?, Object![]?);
     method public boolean yieldIfContendedSafely();
     method public boolean yieldIfContendedSafely(long);
   }
@@ -56,8 +56,8 @@
   public interface SupportSQLiteOpenHelper extends java.io.Closeable {
     method public void close();
     method public String? getDatabaseName();
-    method public androidx.sqlite.db.SupportSQLiteDatabase! getReadableDatabase();
-    method public androidx.sqlite.db.SupportSQLiteDatabase! getWritableDatabase();
+    method public androidx.sqlite.db.SupportSQLiteDatabase getReadableDatabase();
+    method public androidx.sqlite.db.SupportSQLiteDatabase getWritableDatabase();
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public void setWriteAheadLoggingEnabled(boolean);
   }
 
@@ -94,18 +94,18 @@
   }
 
   public interface SupportSQLiteProgram extends java.io.Closeable {
-    method public void bindBlob(int, byte[]!);
+    method public void bindBlob(int, byte[]);
     method public void bindDouble(int, double);
     method public void bindLong(int, long);
     method public void bindNull(int);
-    method public void bindString(int, String!);
+    method public void bindString(int, String);
     method public void clearBindings();
   }
 
   public interface SupportSQLiteQuery {
-    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram!);
+    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram);
     method public int getArgCount();
-    method public String! getSql();
+    method public String getSql();
   }
 
   public final class SupportSQLiteQueryBuilder {
@@ -125,7 +125,7 @@
     method public long executeInsert();
     method public int executeUpdateDelete();
     method public long simpleQueryForLong();
-    method public String! simpleQueryForString();
+    method public String? simpleQueryForString();
   }
 
 }
diff --git a/sqlite/sqlite/api/restricted_current.txt b/sqlite/sqlite/api/restricted_current.txt
index 927cb1b..1014417 100644
--- a/sqlite/sqlite/api/restricted_current.txt
+++ b/sqlite/sqlite/api/restricted_current.txt
@@ -2,34 +2,34 @@
 package androidx.sqlite.db {
 
   public final class SimpleSQLiteQuery implements androidx.sqlite.db.SupportSQLiteQuery {
-    ctor public SimpleSQLiteQuery(String!, Object![]?);
-    ctor public SimpleSQLiteQuery(String!);
-    method public static void bind(androidx.sqlite.db.SupportSQLiteProgram!, Object![]!);
-    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram!);
+    ctor public SimpleSQLiteQuery(String, Object![]?);
+    ctor public SimpleSQLiteQuery(String);
+    method public static void bind(androidx.sqlite.db.SupportSQLiteProgram, Object![]?);
+    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram);
     method public int getArgCount();
-    method public String! getSql();
+    method public String getSql();
   }
 
   public interface SupportSQLiteDatabase extends java.io.Closeable {
     method public void beginTransaction();
     method public void beginTransactionNonExclusive();
-    method public void beginTransactionWithListener(android.database.sqlite.SQLiteTransactionListener!);
-    method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener!);
-    method public androidx.sqlite.db.SupportSQLiteStatement! compileStatement(String!);
-    method public int delete(String!, String!, Object![]!);
+    method public void beginTransactionWithListener(android.database.sqlite.SQLiteTransactionListener);
+    method public void beginTransactionWithListenerNonExclusive(android.database.sqlite.SQLiteTransactionListener);
+    method public androidx.sqlite.db.SupportSQLiteStatement compileStatement(String);
+    method public int delete(String, String?, Object![]?);
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public void disableWriteAheadLogging();
     method public boolean enableWriteAheadLogging();
     method public void endTransaction();
     method public default void execPerConnectionSQL(String, Object![]?);
-    method public void execSQL(String!) throws android.database.SQLException;
-    method public void execSQL(String!, Object![]!) throws android.database.SQLException;
-    method public java.util.List<android.util.Pair<java.lang.String!,java.lang.String!>!>! getAttachedDbs();
+    method public void execSQL(String) throws android.database.SQLException;
+    method public void execSQL(String, Object![]) throws android.database.SQLException;
+    method public java.util.List<android.util.Pair<java.lang.String!,java.lang.String!>!>? getAttachedDbs();
     method public long getMaximumSize();
     method public long getPageSize();
-    method public String! getPath();
+    method public String? getPath();
     method public int getVersion();
     method public boolean inTransaction();
-    method public long insert(String!, int, android.content.ContentValues!) throws android.database.SQLException;
+    method public long insert(String, int, android.content.ContentValues) throws android.database.SQLException;
     method public boolean isDatabaseIntegrityOk();
     method public boolean isDbLockedByCurrentThread();
     method public default boolean isExecPerConnectionSQLSupported();
@@ -37,18 +37,18 @@
     method public boolean isReadOnly();
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public boolean isWriteAheadLoggingEnabled();
     method public boolean needUpgrade(int);
-    method public android.database.Cursor! query(String!);
-    method public android.database.Cursor! query(String!, Object![]!);
-    method public android.database.Cursor! query(androidx.sqlite.db.SupportSQLiteQuery!);
-    method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public android.database.Cursor! query(androidx.sqlite.db.SupportSQLiteQuery!, android.os.CancellationSignal!);
+    method public android.database.Cursor query(String);
+    method public android.database.Cursor query(String, Object![]);
+    method public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery);
+    method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery, android.os.CancellationSignal?);
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public void setForeignKeyConstraintsEnabled(boolean);
-    method public void setLocale(java.util.Locale!);
+    method public void setLocale(java.util.Locale);
     method public void setMaxSqlCacheSize(int);
     method public long setMaximumSize(long);
     method public void setPageSize(long);
     method public void setTransactionSuccessful();
     method public void setVersion(int);
-    method public int update(String!, int, android.content.ContentValues!, String!, Object![]!);
+    method public int update(String, int, android.content.ContentValues, String?, Object![]?);
     method public boolean yieldIfContendedSafely();
     method public boolean yieldIfContendedSafely(long);
   }
@@ -56,8 +56,8 @@
   public interface SupportSQLiteOpenHelper extends java.io.Closeable {
     method public void close();
     method public String? getDatabaseName();
-    method public androidx.sqlite.db.SupportSQLiteDatabase! getReadableDatabase();
-    method public androidx.sqlite.db.SupportSQLiteDatabase! getWritableDatabase();
+    method public androidx.sqlite.db.SupportSQLiteDatabase getReadableDatabase();
+    method public androidx.sqlite.db.SupportSQLiteDatabase getWritableDatabase();
     method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN) public void setWriteAheadLoggingEnabled(boolean);
   }
 
@@ -94,18 +94,18 @@
   }
 
   public interface SupportSQLiteProgram extends java.io.Closeable {
-    method public void bindBlob(int, byte[]!);
+    method public void bindBlob(int, byte[]);
     method public void bindDouble(int, double);
     method public void bindLong(int, long);
     method public void bindNull(int);
-    method public void bindString(int, String!);
+    method public void bindString(int, String);
     method public void clearBindings();
   }
 
   public interface SupportSQLiteQuery {
-    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram!);
+    method public void bindTo(androidx.sqlite.db.SupportSQLiteProgram);
     method public int getArgCount();
-    method public String! getSql();
+    method public String getSql();
   }
 
   public final class SupportSQLiteQueryBuilder {
@@ -125,7 +125,7 @@
     method public long executeInsert();
     method public int executeUpdateDelete();
     method public long simpleQueryForLong();
-    method public String! simpleQueryForString();
+    method public String? simpleQueryForString();
   }
 
 }
diff --git a/sqlite/sqlite/lint-baseline.xml b/sqlite/sqlite/lint-baseline.xml
index 0d56396..f6fbbb4 100644
--- a/sqlite/sqlite/lint-baseline.xml
+++ b/sqlite/sqlite/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
diff --git a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SimpleSQLiteQuery.java b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SimpleSQLiteQuery.java
index 58c330c..b5e3ba7 100644
--- a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SimpleSQLiteQuery.java
+++ b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SimpleSQLiteQuery.java
@@ -16,6 +16,7 @@
 
 package androidx.sqlite.db;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 /**
@@ -33,7 +34,7 @@
      * @param query    The query string, can include bind arguments (.e.g ?).
      * @param bindArgs The bind argument value that will replace the placeholders in the query.
      */
-    public SimpleSQLiteQuery(String query, @Nullable Object[] bindArgs) {
+    public SimpleSQLiteQuery(@NonNull String query, @Nullable Object[] bindArgs) {
         mQuery = query;
         mBindArgs = bindArgs;
     }
@@ -43,17 +44,18 @@
      *
      * @param query The SQL query to execute. Cannot include bind parameters.
      */
-    public SimpleSQLiteQuery(String query) {
+    public SimpleSQLiteQuery(@NonNull String query) {
         this(query, null);
     }
 
+    @NonNull
     @Override
     public String getSql() {
         return mQuery;
     }
 
     @Override
-    public void bindTo(SupportSQLiteProgram statement) {
+    public void bindTo(@NonNull SupportSQLiteProgram statement) {
         bind(statement, mBindArgs);
     }
 
@@ -68,7 +70,7 @@
      * @param statement The sqlite statement
      * @param bindArgs  The list of bind arguments
      */
-    public static void bind(SupportSQLiteProgram statement, Object[] bindArgs) {
+    public static void bind(@NonNull SupportSQLiteProgram statement, @Nullable Object[] bindArgs) {
         if (bindArgs == null) {
             return;
         }
diff --git a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteDatabase.java b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteDatabase.java
index 4b17a66..1a5d17e 100644
--- a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteDatabase.java
+++ b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteDatabase.java
@@ -47,7 +47,8 @@
      * @param sql The sql query.
      * @return Compiled statement.
      */
-    SupportSQLiteStatement compileStatement(String sql);
+    @NonNull
+    SupportSQLiteStatement compileStatement(@NonNull String sql);
 
     /**
      * Begins a transaction in EXCLUSIVE mode.
@@ -119,7 +120,7 @@
      *                            commits, or is rolled back, either explicitly or by a call to
      *                            {@link #yieldIfContendedSafely}.
      */
-    void beginTransactionWithListener(SQLiteTransactionListener transactionListener);
+    void beginTransactionWithListener(@NonNull SQLiteTransactionListener transactionListener);
 
     /**
      * Begins a transaction in IMMEDIATE mode. Transactions can be nested. When
@@ -145,7 +146,8 @@
      *                            transaction begins, commits, or is rolled back, either
      *                            explicitly or by a call to {@link #yieldIfContendedSafely}.
      */
-    void beginTransactionWithListenerNonExclusive(SQLiteTransactionListener transactionListener);
+    void beginTransactionWithListenerNonExclusive(
+            @NonNull SQLiteTransactionListener transactionListener);
 
     /**
      * End a transaction. See beginTransaction for notes about how to use this and when transactions
@@ -308,20 +310,22 @@
      * {@link Cursor}s are not synchronized, see the documentation for more details.
      * @see #query(SupportSQLiteQuery)
      */
-    Cursor query(String query);
+    @NonNull
+    Cursor query(@NonNull String query);
 
     /**
      * Runs the given query on the database. If you would like to have bind arguments,
      * use {@link #query(SupportSQLiteQuery)}.
      *
-     * @param query The SQL query that includes the query and can bind into a given compiled
-     *              program.
+     * @param query    The SQL query that includes the query and can bind into a given compiled
+     *                 program.
      * @param bindArgs The query arguments to bind.
      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
      * {@link Cursor}s are not synchronized, see the documentation for more details.
      * @see #query(SupportSQLiteQuery)
      */
-    Cursor query(String query, Object[] bindArgs);
+    @NonNull
+    Cursor query(@NonNull String query, @NonNull Object[] bindArgs);
 
     /**
      * Runs the given query on the database.
@@ -334,7 +338,8 @@
      * {@link Cursor}s are not synchronized, see the documentation for more details.
      * @see SimpleSQLiteQuery
      */
-    Cursor query(SupportSQLiteQuery query);
+    @NonNull
+    Cursor query(@NonNull SupportSQLiteQuery query);
 
     /**
      * Runs the given query on the database.
@@ -349,8 +354,10 @@
      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
      * {@link Cursor}s are not synchronized, see the documentation for more details.
      */
+    @NonNull
     @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
-    Cursor query(SupportSQLiteQuery query, CancellationSignal cancellationSignal);
+    Cursor query(@NonNull SupportSQLiteQuery query,
+            @Nullable CancellationSignal cancellationSignal);
 
     /**
      * Convenience method for inserting a row into the database.
@@ -366,7 +373,8 @@
      * @return the row ID of the newly inserted row, or -1 if an error occurred
      * @throws SQLException If the insert fails
      */
-    long insert(String table, int conflictAlgorithm, ContentValues values) throws SQLException;
+    long insert(@NonNull String table, int conflictAlgorithm, @NonNull ContentValues values)
+            throws SQLException;
 
     /**
      * Convenience method for deleting rows in the database.
@@ -381,7 +389,7 @@
      * otherwise. To remove all rows and get a count pass "1" as the
      * whereClause.
      */
-    int delete(String table, String whereClause, Object[] whereArgs);
+    int delete(@NonNull String table, @Nullable String whereClause, @Nullable Object[] whereArgs);
 
     /**
      * Convenience method for updating rows in the database.
@@ -400,8 +408,8 @@
      *                    will be bound as Strings.
      * @return the number of rows affected
      */
-    int update(String table, int conflictAlgorithm,
-            ContentValues values, String whereClause, Object[] whereArgs);
+    int update(@NonNull String table, int conflictAlgorithm, @NonNull ContentValues values,
+            @Nullable String whereClause, @Nullable Object[] whereArgs);
 
     /**
      * Execute a single SQL statement that does not return any data.
@@ -417,7 +425,7 @@
      * @throws SQLException if the SQL string is invalid
      * @see #query(SupportSQLiteQuery)
      */
-    void execSQL(String sql) throws SQLException;
+    void execSQL(@NonNull String sql) throws SQLException;
 
     /**
      * Execute a single SQL statement that does not return any data.
@@ -435,7 +443,7 @@
      * @throws SQLException if the SQL string is invalid
      * @see #query(SupportSQLiteQuery)
      */
-    void execSQL(String sql, Object[] bindArgs) throws SQLException;
+    void execSQL(@NonNull String sql, @NonNull Object[] bindArgs) throws SQLException;
 
     /**
      * Returns true if the database is opened as read only.
@@ -464,6 +472,7 @@
      *
      * @return The path to the database file.
      */
+    @Nullable
     String getPath();
 
     /**
@@ -476,7 +485,7 @@
      *                      requested.
      *                      In this case the database remains unchanged.
      */
-    void setLocale(Locale locale);
+    void setLocale(@NonNull Locale locale);
 
     /**
      * Sets the maximum size of the prepared-statement cache for this database.
@@ -630,6 +639,8 @@
      * @return ArrayList of pairs of (database name, database file path) or null if the database
      * is not open.
      */
+    @SuppressWarnings("NullableCollection") // Consistent with platform API.
+    @Nullable
     List<Pair<String, String>> getAttachedDbs();
 
     /**
diff --git a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteOpenHelper.java b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteOpenHelper.java
index 55d37ea..0e46c47 100644
--- a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteOpenHelper.java
+++ b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteOpenHelper.java
@@ -16,6 +16,7 @@
 
 package androidx.sqlite.db;
 
+import android.content.ContentProvider;
 import android.content.Context;
 import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteOpenHelper;
@@ -75,11 +76,12 @@
      *
      * <p class="caution">Database upgrade may take a long time, you
      * should not call this method from the application main thread, including
-     * from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
+     * from {@link ContentProvider#onCreate ContentProvider.onCreate()}.
      *
      * @return a read/write database object valid until {@link #close} is called
      * @throws SQLiteException if the database cannot be opened for writing
      */
+    @NonNull
     SupportSQLiteDatabase getWritableDatabase();
 
     /**
@@ -94,12 +96,13 @@
      * <p class="caution">Like {@link #getWritableDatabase}, this method may
      * take a long time to return, so you should not call it from the
      * application main thread, including from
-     * {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
+     * {@link ContentProvider#onCreate ContentProvider.onCreate()}.
      *
      * @return a database object valid until {@link #getWritableDatabase}
      * or {@link #close} is called.
      * @throws SQLiteException if the database cannot be opened
      */
+    @NonNull
     SupportSQLiteDatabase getReadableDatabase();
 
     /**
diff --git a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteProgram.java b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteProgram.java
index 9eeb9b0..cd0a5ef 100644
--- a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteProgram.java
+++ b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteProgram.java
@@ -16,6 +16,8 @@
 
 package androidx.sqlite.db;
 
+import androidx.annotation.NonNull;
+
 import java.io.Closeable;
 
 /**
@@ -57,7 +59,7 @@
      * @param index The 1-based index to the parameter to bind
      * @param value The value to bind, must not be null
      */
-    void bindString(int index, String value);
+    void bindString(int index, @NonNull String value);
 
     /**
      * Bind a byte array value to this statement. The value remains bound until
@@ -66,7 +68,7 @@
      * @param index The 1-based index to the parameter to bind
      * @param value The value to bind, must not be null
      */
-    void bindBlob(int index, byte[] value);
+    void bindBlob(int index, @NonNull byte[] value);
 
     /**
      * Clears all existing bindings. Unset bindings are treated as NULL.
diff --git a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteQuery.java b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteQuery.java
index b631528..82909fc 100644
--- a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteQuery.java
+++ b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteQuery.java
@@ -16,6 +16,8 @@
 
 package androidx.sqlite.db;
 
+import androidx.annotation.NonNull;
+
 /**
  * A query with typed bindings. It is better to use this API instead of
  * {@link android.database.sqlite.SQLiteDatabase#rawQuery(String, String[])} because it allows
@@ -27,6 +29,7 @@
      *
      * @return The SQL query to compile
      */
+    @NonNull
     String getSql();
 
     /**
@@ -34,7 +37,7 @@
      *
      * @param statement The compiled statement
      */
-    void bindTo(SupportSQLiteProgram statement);
+    void bindTo(@NonNull SupportSQLiteProgram statement);
 
     /**
      * Returns the number of arguments in this query. This is equal to the number of placeholders
diff --git a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteStatement.java b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteStatement.java
index 1b136d5..ed00b46 100644
--- a/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteStatement.java
+++ b/sqlite/sqlite/src/main/java/androidx/sqlite/db/SupportSQLiteStatement.java
@@ -16,6 +16,8 @@
 
 package androidx.sqlite.db;
 
+import androidx.annotation.Nullable;
+
 /**
  * An interface to map the behavior of {@link android.database.sqlite.SQLiteStatement}.
  */
@@ -68,5 +70,6 @@
      *
      * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
      */
+    @Nullable
     String simpleQueryForString();
 }
diff --git a/test/ext/junit-gtest/build.gradle b/test/ext/junit-gtest/build.gradle
index d0a4dea..11c513e 100644
--- a/test/ext/junit-gtest/build.gradle
+++ b/test/ext/junit-gtest/build.gradle
@@ -70,6 +70,12 @@
         }
     }
     namespace "androidx.test.ext.junitgtest"
+
+    packagingOptions {
+        jniLibs {
+            excludes += "**/libc++_shared.so"
+        }
+    }
 }
 
 afterEvaluate {
diff --git a/test/ext/junit-gtest/src/main/cpp/CMakeLists.txt b/test/ext/junit-gtest/src/main/cpp/CMakeLists.txt
index cbe6cfa..1c8f7e4 100644
--- a/test/ext/junit-gtest/src/main/cpp/CMakeLists.txt
+++ b/test/ext/junit-gtest/src/main/cpp/CMakeLists.txt
@@ -26,21 +26,4 @@
         -uJava_androidx_test_ext_junitgtest_GtestRunner_initialize
         -uJava_androidx_test_ext_junitgtest_GtestRunner_run
         -uJava_androidx_test_ext_junitgtest_GtestRunner_addTest
-        )
-
-add_library(adder
-        SHARED
-        adder.cpp
-        )
-
-add_library(apptest
-        SHARED
-        app_test.cpp
-        )
-
-target_link_libraries(apptest
-        PRIVATE
-        adder
-        googletest::gtest
-        junit-gtest
         )
\ No newline at end of file
diff --git a/test/integration-tests/junit-gtest-test/OWNERS b/test/integration-tests/junit-gtest-test/OWNERS
new file mode 100644
index 0000000..5cc09b5
--- /dev/null
+++ b/test/integration-tests/junit-gtest-test/OWNERS
@@ -0,0 +1,3 @@
[email protected]
[email protected]
[email protected]
\ No newline at end of file
diff --git a/test/integration-tests/junit-gtest-test/build.gradle b/test/integration-tests/junit-gtest-test/build.gradle
new file mode 100644
index 0000000..c76cbce
--- /dev/null
+++ b/test/integration-tests/junit-gtest-test/build.gradle
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+import androidx.build.LibraryType
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+    api(libs.kotlinStdlib)
+    implementation(libs.junit)
+    implementation(libs.googletest)
+    implementation(project(":test:ext:junit-gtest"))
+    androidTestImplementation(libs.testExtJunit)
+    androidTestImplementation(libs.truth)
+    androidTestImplementation(libs.testCore)
+    androidTestImplementation(libs.testRunner)
+    androidTestImplementation(libs.espressoCore)
+}
+
+android {
+    defaultConfig {
+        minSdkVersion 18
+        externalNativeBuild {
+            cmake {
+                arguments "-DANDROID_STL=c++_shared"
+            }
+        }
+    }
+    externalNativeBuild {
+        cmake {
+            version libs.versions.cmake.get()
+            path "src/main/cpp/CMakeLists.txt"
+        }
+    }
+
+    buildFeatures {
+        prefab = true
+    }
+    namespace "androidx.test.ext.junitgtesttest"
+}
+
diff --git a/wear/compose/compose-material/src/androidAndroidTest/AndroidManifest.xml b/test/integration-tests/junit-gtest-test/src/androidTest/AndroidManifest.xml
similarity index 88%
copy from wear/compose/compose-material/src/androidAndroidTest/AndroidManifest.xml
copy to test/integration-tests/junit-gtest-test/src/androidTest/AndroidManifest.xml
index f405734..4d68dc2 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/AndroidManifest.xml
+++ b/test/integration-tests/junit-gtest-test/src/androidTest/AndroidManifest.xml
@@ -14,5 +14,6 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
-<manifest package="androidx.wear.compose.material.test" />
+</manifest>
diff --git a/test/ext/junit-gtest/src/androidTest/java/androidx/test/ext/junitgtest/GtestRunnerTest.kt b/test/integration-tests/junit-gtest-test/src/androidTest/java/androidx/test/ext/junitgtesttest/GtestRunnerTest.kt
similarity index 73%
rename from test/ext/junit-gtest/src/androidTest/java/androidx/test/ext/junitgtest/GtestRunnerTest.kt
rename to test/integration-tests/junit-gtest-test/src/androidTest/java/androidx/test/ext/junitgtesttest/GtestRunnerTest.kt
index 2511fb3..ac842ad 100644
--- a/test/ext/junit-gtest/src/androidTest/java/androidx/test/ext/junitgtest/GtestRunnerTest.kt
+++ b/test/integration-tests/junit-gtest-test/src/androidTest/java/androidx/test/ext/junitgtesttest/GtestRunnerTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 The Android Open Source Project
+ * 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.
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-package androidx.test.ext.junitgtest
+package androidx.test.ext.junitgtesttest
 
+import androidx.test.ext.junitgtest.GtestRunner
+import androidx.test.ext.junitgtest.TargetLibrary
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.Description
@@ -24,6 +26,15 @@
 import org.junit.runner.notification.RunListener
 import org.junit.runner.notification.RunNotifier
 
+/**
+ * Tests the GtestRunner
+ *
+ * These specific tests would be more appropriate to put in junit-gtest itself, and have an
+ * integration test app run the tests more like an actual app consuming the library would (basically
+ * the [NativeTests] class), but due to b/236913987 it is currently difficult or impossible to
+ * make the test libraries ('apptest') available to the tests without including them in the release
+ * AAR.
+ */
 class GtestRunnerTest {
     private val runListener = CountingRunListener()
     private val runNotifier = RunNotifier().apply {
@@ -51,8 +62,8 @@
         runner.run(runNotifier)
         assertThat(runListener.descriptions.map { it.displayName }).isEqualTo(
             listOf(
-                "adder_pass(androidx.test.ext.junitgtest.GtestRunnerTest\$NativeTests)",
-                "foo_fail(androidx.test.ext.junitgtest.GtestRunnerTest\$NativeTests)")
+                "adder_pass(androidx.test.ext.junitgtesttest.GtestRunnerTest\$NativeTests)",
+                "foo_fail(androidx.test.ext.junitgtesttest.GtestRunnerTest\$NativeTests)")
 
         )
     }
diff --git a/wear/compose/compose-material/src/androidAndroidTest/AndroidManifest.xml b/test/integration-tests/junit-gtest-test/src/main/AndroidManifest.xml
similarity index 88%
rename from wear/compose/compose-material/src/androidAndroidTest/AndroidManifest.xml
rename to test/integration-tests/junit-gtest-test/src/main/AndroidManifest.xml
index f405734..037bd65 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/AndroidManifest.xml
+++ b/test/integration-tests/junit-gtest-test/src/main/AndroidManifest.xml
@@ -14,5 +14,6 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
-<manifest package="androidx.wear.compose.material.test" />
+</manifest>
\ No newline at end of file
diff --git a/test/integration-tests/junit-gtest-test/src/main/cpp/CMakeLists.txt b/test/integration-tests/junit-gtest-test/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000..6163455
--- /dev/null
+++ b/test/integration-tests/junit-gtest-test/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 3.10.2)
+
+project(junit-gtest-test LANGUAGES CXX)
+
+find_package(googletest REQUIRED CONFIG)
+find_package(junit-gtest REQUIRED CONFIG)
+
+add_library(adder
+        SHARED
+        adder.cpp
+        )
+
+add_library(apptest
+        SHARED
+        app_test.cpp
+        )
+
+target_link_libraries(apptest
+        PRIVATE
+        adder
+        googletest::gtest
+        junit-gtest::junit-gtest
+        )
\ No newline at end of file
diff --git a/test/ext/junit-gtest/src/main/cpp/adder.cpp b/test/integration-tests/junit-gtest-test/src/main/cpp/adder.cpp
similarity index 100%
rename from test/ext/junit-gtest/src/main/cpp/adder.cpp
rename to test/integration-tests/junit-gtest-test/src/main/cpp/adder.cpp
diff --git a/test/ext/junit-gtest/src/main/cpp/adder.h b/test/integration-tests/junit-gtest-test/src/main/cpp/adder.h
similarity index 100%
rename from test/ext/junit-gtest/src/main/cpp/adder.h
rename to test/integration-tests/junit-gtest-test/src/main/cpp/adder.h
diff --git a/test/ext/junit-gtest/src/main/cpp/app_test.cpp b/test/integration-tests/junit-gtest-test/src/main/cpp/app_test.cpp
similarity index 100%
rename from test/ext/junit-gtest/src/main/cpp/app_test.cpp
rename to test/integration-tests/junit-gtest-test/src/main/cpp/app_test.cpp
diff --git a/test/uiautomator/integration-tests/testapp/build.gradle b/test/uiautomator/integration-tests/testapp/build.gradle
index 1ffcac4..27d8d22 100644
--- a/test/uiautomator/integration-tests/testapp/build.gradle
+++ b/test/uiautomator/integration-tests/testapp/build.gradle
@@ -20,6 +20,8 @@
 }
 
 dependencies {
+    implementation("androidx.annotation:annotation:1.4.0")
+
     androidTestImplementation(project(":test:uiautomator:uiautomator"))
     androidTestImplementation(libs.testCore)
     androidTestImplementation(libs.testExtJunit)
diff --git a/test/uiautomator/integration-tests/testapp/lint-baseline.xml b/test/uiautomator/integration-tests/testapp/lint-baseline.xml
index 0e0e653..61e4ed9 100644
--- a/test/uiautomator/integration-tests/testapp/lint-baseline.xml
+++ b/test/uiautomator/integration-tests/testapp/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha01" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha01)" variant="all" version="7.4.0-alpha01">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="DuplicateIds"
@@ -17,191 +17,4 @@
             message="Duplicate id `@+id/shared_id` originally defined here"/>
     </issue>
 
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/BySelectorTestClazzActivity.java"
-            line="27"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/BySelectorTestDescActivity.java"
-            line="29"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/BySelectorTestHasChildActivity.java"
-            line="28"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/BySelectorTestResActivity.java"
-            line="28"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/BySelectorTestTextActivity.java"
-            line="28"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/MainActivity.java"
-            line="28"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClearTextActivity.java"
-            line="27"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickActivity.java"
-            line="30"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onButtonClick(View v) {"
-        errorLine2="                              ~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickActivity.java"
-            line="36"
-            column="31"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickAndWaitActivity.java"
-            line="31"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void launchNewWindow(View v) {"
-        errorLine2="                                ~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickAndWaitActivity.java"
-            line="37"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickAndWaitConfirmActivity.java"
-            line="28"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/UiObject2TestGetClassNameActivity.java"
-            line="28"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/UiObject2TestLongClickActivity.java"
-            line="30"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onButtonLongClick(View v) {"
-        errorLine2="                                  ~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/UiObject2TestLongClickActivity.java"
-            line="44"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/UiObject2TestPinchActivity.java"
-            line="35"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/testapp/UiObject2TestVerticalScrollActivity.java"
-            line="35"
-            column="26"/>
-    </issue>
-
 </issues>
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java
index 38e6ca3..69a2db2 100644
--- a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java
@@ -20,16 +20,9 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.ProgressBar;
 import android.widget.RadioButton;
 import android.widget.RatingBar;
-import android.widget.SeekBar;
-import android.widget.Switch;
-import android.widget.TextView;
-import android.widget.ToggleButton;
+import android.widget.VideoView;
 
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.BySelector;
@@ -37,6 +30,8 @@
 
 import org.junit.Test;
 
+import java.util.regex.Pattern;
+
 public class BySelectorTests extends BaseTest {
 
     @Test
@@ -56,157 +51,77 @@
     }
 
     @Test
-    public void testClazzButton() {
+    public void testClazz() {
         launchTestActivity(BySelectorTestClazzActivity.class);
 
-        // Button
-        assertNotNull(mDevice.findObject(By.clazz("android.widget", "Button")));
+        // Single string combining package name and class name.
         assertNotNull(mDevice.findObject(By.clazz("android.widget.Button")));
-        assertNotNull(mDevice.findObject(By.clazz(".Button")));
-        assertNotNull(mDevice.findObject(By.clazz(Button.class)));
-    }
-
-    @Test
-    public void testClazzCheckBox() {
-        launchTestActivity(BySelectorTestClazzActivity.class);
-
-        // CheckBox
-        assertNotNull(mDevice.findObject(By.clazz("android.widget", "CheckBox")));
         assertNotNull(mDevice.findObject(By.clazz("android.widget.CheckBox")));
-        assertNotNull(mDevice.findObject(By.clazz(".CheckBox")));
-        assertNotNull(mDevice.findObject(By.clazz(CheckBox.class)));
-    }
-
-    @Test
-    public void testClazzEditText() {
-        launchTestActivity(BySelectorTestClazzActivity.class);
-
-        // EditText
-        assertNotNull(mDevice.findObject(By.clazz("android.widget", "EditText")));
-        assertNotNull(mDevice.findObject(By.clazz("android.widget.EditText")));
-        assertNotNull(mDevice.findObject(By.clazz(".EditText")));
-        assertNotNull(mDevice.findObject(By.clazz(EditText.class)));
-    }
-
-    @Test
-    public void testClazzProgressBar() {
-        launchTestActivity(BySelectorTestClazzActivity.class);
-
-        // ProgressBar
-        assertNotNull(mDevice.findObject(By.clazz("android.widget", "ProgressBar")));
-        assertNotNull(mDevice.findObject(By.clazz("android.widget.ProgressBar")));
-        assertNotNull(mDevice.findObject(By.clazz(".ProgressBar")));
-        assertNotNull(mDevice.findObject(By.clazz(ProgressBar.class)));
-    }
-
-    @Test
-    public void testClazzRadioButton() {
-        launchTestActivity(BySelectorTestClazzActivity.class);
-
-        // RadioButton
-        assertNotNull(mDevice.findObject(By.clazz("android.widget", "RadioButton")));
-        assertNotNull(mDevice.findObject(By.clazz("android.widget.RadioButton")));
-        assertNotNull(mDevice.findObject(By.clazz(".RadioButton")));
-        assertNotNull(mDevice.findObject(By.clazz(RadioButton.class)));
-    }
-
-    @Test
-    public void testClazzRatingBar() {
-        launchTestActivity(BySelectorTestClazzActivity.class);
-
-        // RatingBar
-        assertNotNull(mDevice.findObject(By.clazz("android.widget", "RatingBar")));
-        assertNotNull(mDevice.findObject(By.clazz("android.widget.RatingBar")));
-        assertNotNull(mDevice.findObject(By.clazz(".RatingBar")));
-        assertNotNull(mDevice.findObject(By.clazz(RatingBar.class)));
-    }
-
-    @Test
-    public void testClazzSeekBar() {
-        launchTestActivity(BySelectorTestClazzActivity.class);
-
-        // SeekBar
-        assertNotNull(mDevice.findObject(By.clazz("android.widget", "SeekBar")));
-        assertNotNull(mDevice.findObject(By.clazz("android.widget.SeekBar")));
-        assertNotNull(mDevice.findObject(By.clazz(".SeekBar")));
-        assertNotNull(mDevice.findObject(By.clazz(SeekBar.class)));
-    }
-
-    @Test
-    public void testClazzSwitch() {
-        launchTestActivity(BySelectorTestClazzActivity.class);
-
-        // Switch
-        assertNotNull(mDevice.findObject(By.clazz("android.widget", "Switch")));
-        assertNotNull(mDevice.findObject(By.clazz("android.widget.Switch")));
-        assertNotNull(mDevice.findObject(By.clazz(".Switch")));
-        assertNotNull(mDevice.findObject(By.clazz(Switch.class)));
-    }
-
-    @Test
-    public void testClazzTextView() {
-        launchTestActivity(BySelectorTestClazzActivity.class);
-
-        // TextView
-        assertNotNull(mDevice.findObject(By.clazz("android.widget", "TextView")));
-        assertNotNull(mDevice.findObject(By.clazz("android.widget.TextView")));
-        assertNotNull(mDevice.findObject(By.clazz(".TextView")));
-        assertNotNull(mDevice.findObject(By.clazz(TextView.class)));
-    }
-
-    @Test
-    public void testClazzToggleButton() {
-        launchTestActivity(BySelectorTestClazzActivity.class);
-
-        // ToggleButton
-        assertNotNull(mDevice.findObject(By.clazz("android.widget", "ToggleButton")));
-        assertNotNull(mDevice.findObject(By.clazz("android.widget.ToggleButton")));
-        assertNotNull(mDevice.findObject(By.clazz(".ToggleButton")));
-        assertNotNull(mDevice.findObject(By.clazz(ToggleButton.class)));
-    }
-
-    @Test
-    public void testClazzNotFound() {
-        launchTestActivity(BySelectorTestClazzActivity.class);
-
-        // Non-existent class
-        assertNull(mDevice.findObject(By.clazz("android.widget", "NonExistentClass")));
         assertNull(mDevice.findObject(By.clazz("android.widget.NonExistentClass")));
+
+        // Single string as partial class name, starting with a dot.
+        // The package will be assumed as `android.widget`.
+        assertNotNull(mDevice.findObject(By.clazz(".SeekBar")));
+        assertNotNull(mDevice.findObject(By.clazz(".Switch")));
         assertNull(mDevice.findObject(By.clazz(".NonExistentClass")));
-    }
 
-    // TODO(b/235841286): Implement these for clazz():
-    // 1. Custom class
-    // 2. Patterns
-    // 3. Runtime Widgets
+        // Two separate strings as package name and class name.
+        assertNotNull(mDevice.findObject(By.clazz("android.widget", "EditText")));
+        assertNotNull(mDevice.findObject(By.clazz("android.widget", "ProgressBar")));
+        assertNull(mDevice.findObject(By.clazz("android.widget", "NonExistentClass")));
 
-    @Test
-    public void testDescSetFromResource() {
-        launchTestActivity(BySelectorTestDescActivity.class);
+        // Class directly.
+        assertNotNull(mDevice.findObject(By.clazz(RadioButton.class)));
+        assertNotNull(mDevice.findObject(By.clazz(RatingBar.class)));
+        assertNull(mDevice.findObject(By.clazz(VideoView.class)));
 
-        // Content Description from resource
-        assertNotNull(mDevice.findObject(By.desc("Content Description Set From Layout")));
+        // Pattern of the class name.
+        assertNotNull(mDevice.findObject(By.clazz(Pattern.compile(".*TextView"))));
+        assertNotNull(mDevice.findObject(By.clazz(Pattern.compile(".*get\\.C.*"))));
+        assertNull(mDevice.findObject(By.clazz(Pattern.compile(".*TextView.+"))));
     }
 
     @Test
-    public void testDescSetAtRuntime() {
+    public void testDesc() {
         launchTestActivity(BySelectorTestDescActivity.class);
 
-        // Content Description set at runtime
-        assertNotNull(mDevice.findObject(By.desc("Content Description Set At Runtime")));
+        // Content description from source code.
+        assertNotNull(mDevice.findObject(By.desc("This button desc contains some text.")));
+
+        // Content description set at runtime.
+        assertNotNull(mDevice.findObject(By.desc("Content description set at runtime.")));
+
+        // No element has this content description.
+        assertNull(mDevice.findObject(By.desc("No element has this content description.")));
+
+        // Pattern of the content description.
+        assertNotNull(mDevice.findObject(By.desc(Pattern.compile(".*contains.*"))));
+        assertNull(mDevice.findObject(By.desc(Pattern.compile(".*NonExistent.*"))));
     }
 
     @Test
-    public void testDescNotFound() {
+    public void testDescContains() {
         launchTestActivity(BySelectorTestDescActivity.class);
 
-        // No element has this content description
-        assertNull(mDevice.findObject(By.desc("No element has this Content Description")));
+        assertNotNull(mDevice.findObject(By.descContains("contains")));
+        assertNull(mDevice.findObject(By.descContains("not-containing")));
     }
 
-    // TODO(b/235841286): Implement these for desc():
-    // 1. Patterns
-    // 2. Runtime Widgets
+    @Test
+    public void testDescStartsWith() {
+        launchTestActivity(BySelectorTestDescActivity.class);
+
+        assertNotNull(mDevice.findObject(By.descStartsWith("This")));
+        assertNull(mDevice.findObject(By.descStartsWith("NotThis")));
+    }
+
+    @Test
+    public void testDescEndsWith() {
+        launchTestActivity(BySelectorTestDescActivity.class);
+
+        assertNotNull(mDevice.findObject(By.descEndsWith(" text.")));
+        assertNull(mDevice.findObject(By.descEndsWith(" not.")));
+    }
 
     @Test
     public void testPackage() {
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java
index 1b68195..3108d5b 100644
--- a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java
@@ -18,13 +18,14 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.os.SystemClock;
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.uiautomator.By;
@@ -34,12 +35,16 @@
 
 import org.junit.Test;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 public class UiObject2Tests extends BaseTest {
+    private static final int TIMEOUT_MS = 10_000;
+    private static final int SPEED_MS = 100;
 
     @Test
-    public void testClearTextField() {
+    public void testClear() {
         launchTestActivity(UiObject2TestClearTextActivity.class);
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "edit_text"));
@@ -51,23 +56,17 @@
     }
 
     @Test
-    public void testClickButton() {
+    public void testClick() {
         launchTestActivity(UiObject2TestClickActivity.class);
 
         // Find the button and verify its initial state
         UiObject2 button = mDevice.findObject(By.res(TEST_APP, "button"));
         assertEquals("Click Me!", button.getText());
-        SystemClock.sleep(1000);
 
         // Click on the button and verify that the text has changed
         button.click();
-        button.wait(Until.textEquals("I've been clicked!"), 10000);
+        button.wait(Until.textEquals("I've been clicked!"), TIMEOUT_MS);
         assertEquals("I've been clicked!", button.getText());
-    }
-
-    @Test
-    public void testClickCheckBox() {
-        launchTestActivity(UiObject2TestClickActivity.class);
 
         // Find the checkbox and verify its initial state
         UiObject2 checkbox = mDevice.findObject(By.res(TEST_APP, "check_box"));
@@ -75,17 +74,29 @@
 
         // Click on the checkbox and verify that it is now checked
         checkbox.click();
-        checkbox.wait(Until.checked(true), 10000);
+        checkbox.wait(Until.checked(true), TIMEOUT_MS);
         assertTrue(checkbox.isChecked());
     }
 
     @Test
-    public void testClickAndWaitForNewWindow() {
+    public void testClickAndWait() {
         launchTestActivity(UiObject2TestClickAndWaitActivity.class);
 
         // Click the button and wait for a new window
         UiObject2 button = mDevice.findObject(By.res(TEST_APP, "new_window_button"));
-        button.clickAndWait(Until.newWindow(), 5000);
+        assertTrue(button.clickAndWait(Until.newWindow(), TIMEOUT_MS));
+    }
+
+    @Test
+    public void testEquals() {
+        launchTestActivity(MainActivity.class);
+
+        // Get the same textView object via different methods.
+        UiObject2 textView1 = mDevice.findObject(By.res(TEST_APP, "example_id"));
+        UiObject2 textView2 = mDevice.findObject(By.text("TextView with an id"));
+        assertTrue(textView1.equals(textView2));
+        UiObject2 linearLayout = mDevice.findObject(By.res(TEST_APP, "nested_elements"));
+        assertFalse(textView1.equals(linearLayout));
     }
 
     @Test
@@ -140,93 +151,25 @@
         UiObject2 nestedObject = mDevice.findObject(By.res(TEST_APP, "nested_elements"));
         List<UiObject2> children = nestedObject.getChildren();
         assertEquals(2, children.size());
-        UiObject2 object1 = children.get(0);
-        assertEquals("android.widget.TextView", object1.getClassName());
-        UiObject2 object2 = children.get(1);
-        assertEquals("android.widget.LinearLayout", object2.getClassName());
+        Set<String> childrenClassNames = new HashSet<String>();
+        childrenClassNames.add(children.get(0).getClassName());
+        childrenClassNames.add(children.get(1).getClassName());
+        assertTrue(childrenClassNames.contains("android.widget.TextView"));
+        assertTrue(childrenClassNames.contains("android.widget.LinearLayout"));
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "example_id"));
         assertTrue(object.getChildren().isEmpty());
     }
 
     @Test
-    public void testGetClassNameButton() {
+    public void testGetClassName() {
         launchTestActivity(UiObject2TestGetClassNameActivity.class);
 
-        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "button"));
-        assertEquals("android.widget.Button", object.getClassName());
-    }
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "button"));
+        assertEquals("android.widget.Button", button.getClassName());
 
-    @Test
-    public void testGetClassNameCheckBox() {
-        launchTestActivity(UiObject2TestGetClassNameActivity.class);
-
-        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "check_box"));
-        assertEquals("android.widget.CheckBox", object.getClassName());
-    }
-
-    @Test
-    public void testGetClassNameEditText() {
-        launchTestActivity(UiObject2TestGetClassNameActivity.class);
-
-        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "edit_text"));
-        assertEquals("android.widget.EditText", object.getClassName());
-    }
-
-    @Test
-    public void testGetClassNameProgressBar() {
-        launchTestActivity(UiObject2TestGetClassNameActivity.class);
-
-        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "progress_bar"));
-        assertEquals("android.widget.ProgressBar", object.getClassName());
-    }
-
-    @Test
-    public void testGetClassNameRadioButton() {
-        launchTestActivity(UiObject2TestGetClassNameActivity.class);
-
-        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "radio_button"));
-        assertEquals("android.widget.RadioButton", object.getClassName());
-    }
-
-    @Test
-    public void testGetClassNameRatingBar() {
-        launchTestActivity(UiObject2TestGetClassNameActivity.class);
-
-        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "rating_bar"));
-        assertEquals("android.widget.RatingBar", object.getClassName());
-    }
-
-    @Test
-    public void testGetClassNameSeekBar() {
-        launchTestActivity(UiObject2TestGetClassNameActivity.class);
-
-        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "seek_bar"));
-        assertEquals("android.widget.SeekBar", object.getClassName());
-    }
-
-    @Test
-    public void testGetClassNameSwitch() {
-        launchTestActivity(UiObject2TestGetClassNameActivity.class);
-
-        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "switch_toggle"));
-        assertEquals("android.widget.Switch", object.getClassName());
-    }
-
-    @Test
-    public void testGetClassNameTextView() {
-        launchTestActivity(UiObject2TestGetClassNameActivity.class);
-
-        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "text_view"));
-        assertEquals("android.widget.TextView", object.getClassName());
-    }
-
-    @Test
-    public void testGetClassNameToggleButton() {
-        launchTestActivity(UiObject2TestGetClassNameActivity.class);
-
-        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "toggle_button"));
-        assertEquals("android.widget.ToggleButton", object.getClassName());
+        UiObject2 textView = mDevice.findObject(By.res(TEST_APP, "text_view"));
+        assertEquals("android.widget.TextView", textView.getClassName());
     }
 
     @Test
@@ -313,16 +256,131 @@
     }
 
     @Test
+    public void testHashCode() {
+        launchTestActivity(MainActivity.class);
+
+        // Get the same textView object via different methods.
+        // The same object should have the same hash code.
+        UiObject2 textView1 = mDevice.findObject(By.res(TEST_APP, "example_id"));
+        UiObject2 textView2 = mDevice.findObject(By.text("TextView with an id"));
+        assertEquals(textView1.hashCode(), textView2.hashCode());
+
+        // Different objects should have different hash codes.
+        UiObject2 linearLayout = mDevice.findObject(By.res(TEST_APP, "nested_elements"));
+        assertNotEquals(textView1.hashCode(), linearLayout.hashCode());
+    }
+
+    @Test
     public void testHasObject() {
         launchTestActivity(MainActivity.class);
 
-        UiObject2 object = mDevice.findObject(By.pkg(TEST_APP));
+        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "example_id"));
 
-        assertTrue(object.hasObject(By.text("Text View 1")));
+        assertTrue(object.hasObject(By.text("TextView with an id")));
         assertFalse(object.hasObject(By.text("")));
     }
 
     @Test
+    public void testIsCheckable() {
+        launchTestActivity(UiObject2TestClickActivity.class);
+
+        // CheckBox objects are checkable by default.
+        UiObject2 checkBox = mDevice.findObject(By.res(TEST_APP, "check_box"));
+        assertTrue(checkBox.isCheckable());
+        // Button objects are not checkable by default.
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "button"));
+        assertFalse(button.isCheckable());
+    }
+
+    @Test
+    public void testIsChecked() {
+        launchTestActivity(UiObject2TestClickActivity.class);
+
+        UiObject2 checkBox = mDevice.findObject(By.res(TEST_APP, "check_box"));
+        assertFalse(checkBox.isChecked());
+        checkBox.click();
+        assertTrue(checkBox.isChecked());
+    }
+
+    @Test
+    public void testIsClickable() {
+        launchTestActivity(MainActivity.class);
+
+        // TextView objects are not clickable by default.
+        UiObject2 textView = mDevice.findObject(By.text("Sample text"));
+        assertFalse(textView.isClickable());
+        // Button objects are clickable by default.
+        UiObject2 button = mDevice.findObject(By.text("Accessible button"));
+        assertTrue(button.isClickable());
+    }
+
+    @Test
+    public void testIsEnabled() {
+        launchTestActivity(UiObject2TestIsEnabledActivity.class);
+
+        UiObject2 disabledObject = mDevice.findObject(By.res(TEST_APP, "disabled_text_view"));
+        assertFalse(disabledObject.isEnabled());
+        UiObject2 enabledObject = mDevice.findObject(By.res(TEST_APP, "enabled_text_view"));
+        assertTrue(enabledObject.isEnabled());
+    }
+
+    @Test
+    public void testIsFocusable() {
+        launchTestActivity(UiObject2TestIsFocusedActivity.class);
+
+        UiObject2 nonFocusableTextView = mDevice.findObject(By.res(TEST_APP,
+                "non_focusable_text_view"));
+        assertFalse(nonFocusableTextView.isFocusable());
+        UiObject2 focusableTextView = mDevice.findObject(By.res(TEST_APP, "focusable_text_view"));
+        assertTrue(focusableTextView.isFocusable());
+    }
+
+    @Test
+    public void testIsFocused() {
+        launchTestActivity(UiObject2TestIsFocusedActivity.class);
+
+        UiObject2 textView = mDevice.findObject(By.res(TEST_APP, "focusable_text_view"));
+        assertFalse(textView.isFocused());
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "button"));
+        button.click();
+        assertTrue(textView.isFocused());
+    }
+
+    @Test
+    public void testIsLongClickable() {
+        launchTestActivity(UiObject2TestIsLongClickableActivity.class);
+
+        UiObject2 longClickableButton = mDevice.findObject(By.res(TEST_APP,
+                "long_clickable_button"));
+        assertTrue(longClickableButton.isLongClickable());
+        UiObject2 nonLongClickableButton = mDevice.findObject(By.res(TEST_APP,
+                "non_long_clickable_button"));
+        assertFalse(nonLongClickableButton.isLongClickable());
+    }
+
+    @Test
+    public void testIsScrollable() {
+        launchTestActivity(UiObject2TestVerticalScrollActivity.class);
+
+        // ScrollView objects are scrollable by default.
+        UiObject2 scrollView = mDevice.findObject(By.res(TEST_APP, "scroll_view"));
+        assertTrue(scrollView.isScrollable());
+        // TextView objects are not scrollable by default.
+        UiObject2 textView = mDevice.findObject(By.res(TEST_APP, "top_text"));
+        assertFalse(textView.isScrollable());
+    }
+
+    @Test
+    public void testIsSelected() {
+        launchTestActivity(UiObject2TestIsSelectedActivity.class);
+
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "selected_button"));
+        button.click();
+        UiObject2 textView = mDevice.findObject(By.res(TEST_APP, "selected_target"));
+        assertTrue(textView.isSelected());
+    }
+
+    @Test
     public void testLongClickButton() {
         launchTestActivity(UiObject2TestLongClickActivity.class);
 
@@ -332,56 +390,79 @@
 
         // Click on the button and verify that the text has changed
         button.longClick();
-        button.wait(Until.textEquals("I've been long clicked!"), 10000);
+        button.wait(Until.textEquals("I've been long clicked!"), TIMEOUT_MS);
         assertEquals("I've been long clicked!", button.getText());
     }
 
     @Test
-    public void testPinchIn100Percent() {
+    public void testPinchClose() {
         launchTestActivity(UiObject2TestPinchActivity.class);
 
-        // Find the area to pinch
         UiObject2 pinchArea = mDevice.findObject(By.res(TEST_APP, "pinch_area"));
         UiObject2 scaleText = pinchArea.findObject(By.res(TEST_APP, "scale_factor"));
-        pinchArea.pinchClose(1.0f, 100);
-        scaleText.wait(Until.textNotEquals("1.0f"), 1000);
+        pinchArea.pinchClose(1f);
+        scaleText.wait(Until.textNotEquals("1.0f"), TIMEOUT_MS);
+        float scaleValueAfterPinch = Float.valueOf(scaleText.getText());
+        assertTrue(String.format("Expected scale value to be less than 1f after pinchClose(), "
+                        + "but got [%f]", scaleValueAfterPinch), scaleValueAfterPinch < 1f);
     }
 
     @Test
-    public void testPinchIn75Percent() {
+    public void testPinchClose_withSpeed() {
         launchTestActivity(UiObject2TestPinchActivity.class);
 
-        // Find the area to pinch
         UiObject2 pinchArea = mDevice.findObject(By.res(TEST_APP, "pinch_area"));
         UiObject2 scaleText = pinchArea.findObject(By.res(TEST_APP, "scale_factor"));
-        pinchArea.pinchClose(.75f, 100);
-        scaleText.wait(Until.textNotEquals("1.0f"), 1000);
+        pinchArea.pinchClose(.75f, SPEED_MS);
+        scaleText.wait(Until.textNotEquals("1.0f"), TIMEOUT_MS);
+        float scaleValueAfterPinch = Float.valueOf(scaleText.getText());
+        assertTrue(String.format("Expected scale value to be less than 1f after pinchClose(), "
+                + "but got [%f]", scaleValueAfterPinch), scaleValueAfterPinch < 1f);
     }
 
     @Test
-    public void testPinchIn50Percent() {
+    public void testPinchOpen() {
         launchTestActivity(UiObject2TestPinchActivity.class);
 
-        // Find the area to pinch
         UiObject2 pinchArea = mDevice.findObject(By.res(TEST_APP, "pinch_area"));
         UiObject2 scaleText = pinchArea.findObject(By.res(TEST_APP, "scale_factor"));
-        pinchArea.pinchClose(.5f, 100);
-        scaleText.wait(Until.textNotEquals("1.0f"), 1000);
+        pinchArea.pinchOpen(.5f);
+        scaleText.wait(Until.textNotEquals("1.0f"), TIMEOUT_MS);
+        float scaleValueAfterPinch = Float.valueOf(scaleText.getText());
+        assertTrue(String.format("Expected scale text to be greater than 1f after pinchOpen(), "
+                + "but got [%f]", scaleValueAfterPinch), scaleValueAfterPinch > 1f);
     }
 
     @Test
-    public void testPinchIn25Percent() {
+    public void testPinchOpen_withSpeed() {
         launchTestActivity(UiObject2TestPinchActivity.class);
 
-        // Find the area to pinch
         UiObject2 pinchArea = mDevice.findObject(By.res(TEST_APP, "pinch_area"));
         UiObject2 scaleText = pinchArea.findObject(By.res(TEST_APP, "scale_factor"));
-        pinchArea.pinchClose(.25f, 100);
-        scaleText.wait(Until.textNotEquals("1.0f"), 1000);
+        pinchArea.pinchOpen(.25f, SPEED_MS);
+        scaleText.wait(Until.textNotEquals("1.0f"), TIMEOUT_MS);
+        float scaleValueAfterPinch = Float.valueOf(scaleText.getText());
+        assertTrue(String.format("Expected scale text to be greater than 1f after pinchOpen(), "
+                + "but got [%f]", scaleValueAfterPinch), scaleValueAfterPinch > 1f);
     }
 
     @Test
-    @FlakyTest
+    public void testRecycle() {
+        launchTestActivity(MainActivity.class);
+
+        UiObject2 textView = mDevice.findObject(By.text("Sample text"));
+        textView.recycle();
+        // Attributes of a recycled object cannot be accessed.
+        IllegalStateException e = assertThrows(
+                "Expected testView.getText() to throw IllegalStateException, but it didn't.",
+                IllegalStateException.class,
+                () -> textView.getText()
+        );
+        assertEquals("This object has already been recycled", e.getMessage());
+    }
+
+    @Test
+    @FlakyTest(bugId = 235841959)
     public void testScrollDown() {
         launchTestActivity(UiObject2TestVerticalScrollActivity.class);
 
@@ -426,7 +507,7 @@
     */
 
     @Test
-    @FlakyTest
+    @FlakyTest(bugId = 235841959)
     public void testScrollDownToEnd() {
         launchTestActivity(UiObject2TestVerticalScrollActivity.class);
 
@@ -435,7 +516,7 @@
 
         // Scroll as much as we can
         UiObject2 scrollView = mDevice.findObject(By.res(TEST_APP, "scroll_view"));
-        scrollView.wait(Until.scrollable(true), 5000);
+        scrollView.wait(Until.scrollable(true), TIMEOUT_MS);
         while (scrollView.scroll(Direction.DOWN, 1.0f)) {
             // Continue until bottom.
         }
@@ -444,37 +525,83 @@
         assertNotNull(mDevice.findObject(By.res(TEST_APP, "bottom_text")));
     }
 
+    @Test
+    public void testSetGestureMargin() {
+        launchTestActivity(UiObject2TestPinchActivity.class);
+
+        UiObject2 pinchArea = mDevice.findObject(By.res(TEST_APP, "pinch_area"));
+        UiObject2 scaleText = pinchArea.findObject(By.res(TEST_APP, "scale_factor"));
+
+        // Set the gesture's margins to a large number (greater than the width or height of the UI
+        // object's visible bounds).
+        // The gesture's bounds cannot form a rectangle and no action can be performed.
+        pinchArea.setGestureMargin(1_000);
+        pinchArea.pinchClose(1f);
+        scaleText.wait(Until.textNotEquals("1.0f"), TIMEOUT_MS);
+        float scaleValueAfterPinch = Float.valueOf(scaleText.getText());
+        assertEquals(String.format("Expected scale value to be equal to 1f after pinchClose(), "
+                + "but got [%f]", scaleValueAfterPinch), 1f, scaleValueAfterPinch, 0f);
+
+        // Set the gesture's margins to a small number (smaller than the width or height of the UI
+        // object's visible bounds).
+        // The gesture's bounds form a rectangle and action can be performed.
+        pinchArea.setGestureMargin(1);
+        pinchArea.pinchClose(1f);
+        scaleText.wait(Until.textNotEquals("1.0f"), TIMEOUT_MS);
+        scaleValueAfterPinch = Float.valueOf(scaleText.getText());
+        assertTrue(String.format("Expected scale value to be less than 1f after pinchClose(), "
+                + "but got [%f]", scaleValueAfterPinch), scaleValueAfterPinch < 1f);
+    }
+
+    @Test
+    public void testSetGestureMargins() {
+        launchTestActivity(UiObject2TestPinchActivity.class);
+
+        UiObject2 pinchArea = mDevice.findObject(By.res(TEST_APP, "pinch_area"));
+        UiObject2 scaleText = pinchArea.findObject(By.res(TEST_APP, "scale_factor"));
+
+        // Set the gesture's margins to large numbers (greater than the width or height of the UI
+        // object's visible bounds).
+        // The gesture's bounds cannot form a rectangle and no action can be performed.
+        pinchArea.setGestureMargins(1, 1, 1_000, 1_000);
+        pinchArea.pinchClose(1f);
+        scaleText.wait(Until.textNotEquals("1.0f"), TIMEOUT_MS);
+        float scaleValueAfterPinch = Float.valueOf(scaleText.getText());
+        assertEquals(String.format("Expected scale value to be equal to 1f after pinchClose(), "
+                + "but got [%f]", scaleValueAfterPinch), 1f, scaleValueAfterPinch, 0f);
+
+        // Set the gesture's margins to small numbers (smaller than the width or height of the UI
+        // object's visible bounds).
+        // The gesture's bounds form a rectangle and action can be performed.
+        pinchArea.setGestureMargins(1, 1, 1, 1);
+        pinchArea.pinchClose(1f);
+        scaleText.wait(Until.textNotEquals("1.0f"), TIMEOUT_MS);
+        scaleValueAfterPinch = Float.valueOf(scaleText.getText());
+        assertTrue(String.format("Expected scale value to be less than 1f after pinchClose(), "
+                + "but got [%f]", scaleValueAfterPinch), scaleValueAfterPinch < 1f);
+    }
+
+    @Test
+    public void testSetText() {
+        launchTestActivity(UiObject2TestClearTextActivity.class);
+
+        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "edit_text"));
+        // Verify the text field has "sample_text" before setText()
+        assertEquals("sample_text", object.getText());
+        object.setText("new_text");
+        // Verify the text field has "new_text" after setText()
+        assertEquals("new_text", object.getText());
+    }
+
     /* TODO(b/235841473): Implement these tests
-    public void testSetText() {}
+    public void testDrag() {}
+
+    public void testFling() {}
+
+    public void testSwipe() {}
 
     public void testWaitForExists() {}
 
     public void testWaitForGone() {}
     */
-
-    /* TODO(b/235841473): Implement more tests
-    public void testDrag() {}
-
-    public void testEquals() {}
-
-    public void testFling() {}
-
-    public void testIsCheckable() {}
-
-    public void testIsChecked() {}
-
-    public void testIsClickable() {}
-
-    public void testIsEnabled() {}
-
-    public void testIsFocusable() {}
-
-    public void testIsFocused() {}
-
-    public void testIsLongClickable() {}
-
-    public void testIsScrollable() {}
-
-    public void testIsSelected() {}
-    */
 }
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UntilTest.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UntilTest.java
new file mode 100644
index 0000000..61d537b
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/UntilTest.java
@@ -0,0 +1,307 @@
+/*
+ * 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.test.uiautomator.testapp;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import org.junit.Test;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/** Integration tests for {@link Until}. */
+@LargeTest
+public class UntilTest extends BaseTest {
+
+    private static final long DELAY_MS = 1_000;
+    private static final long TIMEOUT_MS = 5_000;
+
+    @Test
+    public void testGone() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "gone_button"));
+        BySelector target = By.res(TEST_APP, "gone_target");
+
+        waitForCondition(() -> {
+            assertTrue(mDevice.wait(Until.gone(target), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testHasObject() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "find_button"));
+        BySelector target = By.res(TEST_APP, "find_target");
+
+        waitForCondition(() -> {
+            assertTrue(mDevice.wait(Until.hasObject(target), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testFindObject() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "find_button"));
+        BySelector target = By.res(TEST_APP, "find_target");
+
+        waitForCondition(() -> {
+            assertNotNull(mDevice.wait(Until.findObject(target), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testFindObjects() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "find_button"));
+        BySelector target = By.res(TEST_APP, "find_target");
+
+        waitForCondition(() -> {
+            assertNotNull(mDevice.wait(Until.findObjects(target), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testChecked() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "checked_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "checked_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.checked(true), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testClickable() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "clickable_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "clickable_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.clickable(true), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testEnabled() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "enabled_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "enabled_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.enabled(true), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testFocusable() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "focusable_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "focusable_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.focusable(true), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testFocused() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "focused_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "focused_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.focused(true), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testLongClickable() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "long_clickable_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "long_clickable_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.longClickable(true), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testScrollable() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "scrollable_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "scrollable_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.scrollable(true), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testSelected() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "selected_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "selected_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.selected(true), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testDescMatches() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "desc_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "desc_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.descMatches("update.*desc$"), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testDescEquals() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "desc_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "desc_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.descEquals("updated_desc"), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testDescContains() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "desc_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "desc_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.descContains("updated"), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testDescStartsWith() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "desc_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "desc_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.descStartsWith("updated"), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testDescEndsWith() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "desc_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "desc_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.descEndsWith("ed_desc"), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testTextMatches() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "text_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "text_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.textMatches("update.*text$"), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testTextNotEquals() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "text_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "text_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.textNotEquals("initial_text"), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testTextEquals() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "text_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "text_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.textEquals("updated_text"), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testTextContains() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "text_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "text_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.textContains("updated"), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testTextStartsWith() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "text_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "text_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.textStartsWith("updated"), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    @Test
+    public void testTextEndsWith() {
+        launchTestActivity(UntilTestActivity.class);
+        UiObject2 button = mDevice.findObject(By.res(TEST_APP, "text_button"));
+        UiObject2 target = mDevice.findObject(By.res(TEST_APP, "text_target"));
+
+        waitForCondition(() -> {
+            assertTrue(target.wait(Until.textEndsWith("ed_text"), TIMEOUT_MS));
+        }, button::click);
+    }
+
+    /** Verifies that a condition is met after the required action is executed. */
+    private void waitForCondition(Runnable blockingCondition, Runnable actionToUnblock) {
+        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(0);
+        try {
+            long startTime = System.currentTimeMillis();
+            executorService.schedule(actionToUnblock, DELAY_MS, TimeUnit.MILLISECONDS);
+            blockingCondition.run();
+            long duration = System.currentTimeMillis() - startTime;
+            assertTrue("Condition unblocked before action", DELAY_MS < duration);
+        } finally {
+            executorService.shutdownNow();
+        }
+    }
+}
diff --git a/test/uiautomator/integration-tests/testapp/src/main/AndroidManifest.xml b/test/uiautomator/integration-tests/testapp/src/main/AndroidManifest.xml
index 84728de..308294a 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/AndroidManifest.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -90,6 +90,34 @@
                 <action android:name="android.intent.action.MAIN" />
             </intent-filter>
         </activity>
+        <activity android:name=".UiObject2TestIsEnabledActivity"
+            android:exported="true"
+            android:theme="@android:style/Theme.Holo.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".UiObject2TestIsFocusedActivity"
+            android:exported="true"
+            android:theme="@android:style/Theme.Holo.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".UiObject2TestIsLongClickableActivity"
+            android:exported="true"
+            android:theme="@android:style/Theme.Holo.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".UiObject2TestIsSelectedActivity"
+            android:exported="true"
+            android:theme="@android:style/Theme.Holo.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
         <activity android:name=".UiObject2TestLongClickActivity"
             android:exported="true"
             android:theme="@android:style/Theme.Holo.NoActionBar">
@@ -118,6 +146,13 @@
                 <action android:name="android.intent.action.MAIN" />
             </intent-filter>
         </activity>
+        <activity android:name=".UntilTestActivity"
+            android:exported="true"
+            android:theme="@android:style/Theme.Holo.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
     </application>
 
 </manifest>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestClazzActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestClazzActivity.java
index 22fdb27..c0ed81e 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestClazzActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestClazzActivity.java
@@ -19,12 +19,11 @@
 import android.app.Activity;
 import android.os.Bundle;
 
+import androidx.annotation.Nullable;
+
 public class BySelectorTestClazzActivity extends Activity {
-
-    private static final String TAG = BySelectorTestClazzActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.byselector_testclazz_activity);
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestDescActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestDescActivity.java
index 42505b9..1bfc504 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestDescActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestDescActivity.java
@@ -18,20 +18,18 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
-import android.widget.Button;
+import android.widget.RatingBar;
+
+import androidx.annotation.Nullable;
 
 public class BySelectorTestDescActivity extends Activity {
-
-    private static final String TAG = BySelectorTestDescActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.byselector_testdesc_activity);
 
-        Button button = (Button)findViewById(R.id.button_with_runtime_description);
-        button.setContentDescription("Content Description Set At Runtime");
+        RatingBar rating_bar = (RatingBar) findViewById(R.id.rating_bar);
+        rating_bar.setContentDescription("Content description set at runtime.");
     }
 }
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestHasChildActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestHasChildActivity.java
index 7531ba7..05f04cd 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestHasChildActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestHasChildActivity.java
@@ -18,14 +18,12 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
+
+import androidx.annotation.Nullable;
 
 public class BySelectorTestHasChildActivity extends Activity {
-
-    private static final String TAG = BySelectorTestHasChildActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.byselector_testhaschild_activity);
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestResActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestResActivity.java
index f69a24b..fbf6c0a 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestResActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestResActivity.java
@@ -18,14 +18,12 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
+
+import androidx.annotation.Nullable;
 
 public class BySelectorTestResActivity extends Activity {
-
-    private static final String TAG = BySelectorTestResActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.byselector_testres_activity);
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestTextActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestTextActivity.java
index 0202084..34c0c53 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestTextActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/BySelectorTestTextActivity.java
@@ -18,14 +18,12 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
+
+import androidx.annotation.Nullable;
 
 public class BySelectorTestTextActivity extends Activity {
-
-    private static final String TAG = BySelectorTestTextActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.byselector_testtext_activity);
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/MainActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/MainActivity.java
index f0693e3..e9029c1 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/MainActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/MainActivity.java
@@ -18,14 +18,12 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
+
+import androidx.annotation.Nullable;
 
 public class MainActivity extends Activity {
-
-    private static final String TAG = MainActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.main_activity);
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClearTextActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClearTextActivity.java
index 0a90537..6a816ba 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClearTextActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClearTextActivity.java
@@ -19,12 +19,12 @@
 import android.app.Activity;
 import android.os.Bundle;
 
+import androidx.annotation.Nullable;
+
 public class UiObject2TestClearTextActivity extends Activity {
 
-    private static final String TAG = UiObject2TestClearTextActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.uiobject2_testcleartext_activity);
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickActivity.java
index d644fa4..ec0e5e1 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickActivity.java
@@ -18,22 +18,22 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.View;
 import android.widget.Button;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 public class UiObject2TestClickActivity extends Activity {
 
-    private static final String TAG = UiObject2TestClickActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.uiobject2_testclick_activity);
     }
 
-    public void onButtonClick(View v) {
+    public void onButtonClick(@NonNull View v) {
         ((Button)v).setText("I've been clicked!");
     }
 }
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickAndWaitActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickAndWaitActivity.java
index c14404f..79e46dd 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickAndWaitActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickAndWaitActivity.java
@@ -19,22 +19,21 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.View;
-import android.widget.Button;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 public class UiObject2TestClickAndWaitActivity extends Activity {
 
-    private static final String TAG = UiObject2TestClickActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.uiobject2_testclickandwait_activity);
     }
 
-    public void launchNewWindow(View v) {
+    public void launchNewWindow(@NonNull View v) {
         Intent intent = new Intent(this, UiObject2TestClickAndWaitConfirmActivity.class);
         startActivity(intent);
     }
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickAndWaitConfirmActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickAndWaitConfirmActivity.java
index b181d83..72fd28a 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickAndWaitConfirmActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestClickAndWaitConfirmActivity.java
@@ -18,14 +18,13 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
+
+import androidx.annotation.Nullable;
 
 public class UiObject2TestClickAndWaitConfirmActivity extends Activity {
 
-    private static final String TAG = UiObject2TestClickActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.uiobject2_testclickandwaitconfirm_activity);
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestGetClassNameActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestGetClassNameActivity.java
index c6a6d70..6777abc 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestGetClassNameActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestGetClassNameActivity.java
@@ -18,14 +18,13 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
+
+import androidx.annotation.Nullable;
 
 public class UiObject2TestGetClassNameActivity extends Activity {
 
-    private static final String TAG = UiObject2TestGetClassNameActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         // Reuse layout from BySelectorTestClazz
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsEnabledActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsEnabledActivity.java
new file mode 100644
index 0000000..e5059b2
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsEnabledActivity.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.uiautomator.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+
+public class UiObject2TestIsEnabledActivity extends Activity {
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.uiobject2_testisenabled_activity);
+    }
+}
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsFocusedActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsFocusedActivity.java
new file mode 100644
index 0000000..a2bbb18
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsFocusedActivity.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.uiautomator.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+public class UiObject2TestIsFocusedActivity extends Activity {
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.uiobject2_testisfocused_activity);
+
+        Button focusedButton = (Button) findViewById(R.id.button);
+        TextView focusedTarget = (TextView) findViewById(R.id.focusable_text_view);
+        focusedButton.setOnClickListener(v -> focusedTarget.requestFocus());
+    }
+}
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsLongClickableActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsLongClickableActivity.java
new file mode 100644
index 0000000..6684417
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsLongClickableActivity.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test.uiautomator.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+
+public class UiObject2TestIsLongClickableActivity extends Activity {
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.uiobject2_testislongclickable_activity);
+    }
+}
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsSelectedActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsSelectedActivity.java
new file mode 100644
index 0000000..fc468af
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestIsSelectedActivity.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.uiautomator.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+public class UiObject2TestIsSelectedActivity extends Activity {
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.uiobject2_testisselected_activity);
+
+        Button selectedButton = (Button) findViewById(R.id.selected_button);
+        TextView selectedTarget = (TextView) findViewById(R.id.selected_target);
+        selectedButton.setOnClickListener(v -> selectedTarget.setSelected(true));
+    }
+}
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestLongClickActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestLongClickActivity.java
index 91ff485..30d3627 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestLongClickActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestLongClickActivity.java
@@ -18,30 +18,25 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.View;
 import android.widget.Button;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 public class UiObject2TestLongClickActivity extends Activity {
 
-    private static final String TAG = UiObject2TestLongClickActivity.class.getSimpleName();
-
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.uiobject2_testlongclick_activity);
 
         Button button = (Button)findViewById(R.id.button);
-        button.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                onButtonLongClick(v);
-            }
-        });
+        button.setOnClickListener(this::onButtonLongClick);
     }
 
-    public void onButtonLongClick(View v) {
+    public void onButtonLongClick(@NonNull View v) {
         ((Button)v).setText("I've been long clicked!");
     }
 }
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestPinchActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestPinchActivity.java
index d4a729e..d205048 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestPinchActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestPinchActivity.java
@@ -22,22 +22,20 @@
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
-import android.view.View;
 import android.widget.TextView;
 
-public class UiObject2TestPinchActivity extends Activity {
+import androidx.annotation.Nullable;
 
-    private static final String TAG = UiObject2TestPinchActivity.class.getSimpleName();
+public class UiObject2TestPinchActivity extends Activity {
 
     private ScaleGestureDetector mScaleDetector;
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.uiobject2_testpinch_activity);
 
-        //LinearLayout pinchArea = (LinearLayout)findViewById(R.id.pinch_area);
         final TextView scaleFactor = (TextView)findViewById(R.id.scale_factor);
 
         mScaleDetector = new ScaleGestureDetector(this, new SimpleOnScaleGestureListener() {
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestVerticalScrollActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestVerticalScrollActivity.java
index 59c3ee2..12bd767 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestVerticalScrollActivity.java
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UiObject2TestVerticalScrollActivity.java
@@ -17,7 +17,6 @@
 package androidx.test.uiautomator.testapp;
 
 import android.app.Activity;
-import android.graphics.Rect;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.GestureDetector;
@@ -25,26 +24,18 @@
 import android.view.MotionEvent;
 import android.widget.TextView;
 
-public class UiObject2TestVerticalScrollActivity extends Activity {
+import androidx.annotation.Nullable;
 
-    private static final String TAG = UiObject2TestVerticalScrollActivity.class.getSimpleName();
+public class UiObject2TestVerticalScrollActivity extends Activity {
 
     private GestureDetector mGestureDetector;
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.uiobject2_testverticalscroll_activity);
 
-        /*
-        final TextView topText = (TextView)findViewById(R.id.top_text);
-        Log.d("FOO", String.format("top_text: %s, %s, %s, %s", topText.getLeft(), topText.getTop(), topText.getRight(), topText.getBottom()));
-        final TextView fromTop5000 = (TextView)findViewById(R.id.from_top_5000);
-        Log.d("FOO", String.format("from_top_5000: %s, %s, %s, %s", fromTop5000.getLeft(), fromTop5000.getTop(), fromTop5000.getRight(), fromTop5000.getBottom()));
-        final TextView fromTop10000 = (TextView)findViewById(R.id.from_top_10000);
-        final TextView fromTop15000 = (TextView)findViewById(R.id.from_top_15000);
-*/
         final TextView flingDetected = (TextView)findViewById(R.id.fling_detected);
 
         mGestureDetector = new GestureDetector(this, new SimpleOnGestureListener() {
diff --git a/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UntilTestActivity.java b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UntilTestActivity.java
new file mode 100644
index 0000000..8ea9921
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/main/java/androidx/test/uiautomator/testapp/UntilTestActivity.java
@@ -0,0 +1,92 @@
+/*
+ * 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.test.uiautomator.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+/**
+ * {@link Activity} for testing {@link androidx.test.uiautomator.Until} functionality. Contains
+ * a series of buttons and views that fulfill specific conditions.
+ */
+public class UntilTestActivity extends Activity {
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.until_test_activity);
+
+        Button goneButton = (Button) findViewById(R.id.gone_button);
+        TextView goneTarget = (TextView) findViewById(R.id.gone_target);
+        goneButton.setOnClickListener(v -> goneTarget.setVisibility(View.GONE));
+
+        Button findButton = (Button) findViewById(R.id.find_button);
+        TextView findTarget = (TextView) findViewById(R.id.find_target);
+        findButton.setOnClickListener(v -> findTarget.setVisibility(View.VISIBLE));
+
+        Button checkedButton = (Button) findViewById(R.id.checked_button);
+        CheckBox checkedTarget = (CheckBox) findViewById(R.id.checked_target);
+        checkedButton.setOnClickListener(v -> checkedTarget.setChecked(true));
+
+        Button clickableButton = (Button) findViewById(R.id.clickable_button);
+        TextView clickableTarget = (TextView) findViewById(R.id.clickable_target);
+        clickableButton.setOnClickListener(v -> clickableTarget.setClickable(true));
+
+        Button enabledButton = (Button) findViewById(R.id.enabled_button);
+        TextView enabledTarget = (TextView) findViewById(R.id.enabled_target);
+        enabledButton.setOnClickListener(v -> enabledTarget.setEnabled(true));
+
+        Button focusableButton = (Button) findViewById(R.id.focusable_button);
+        TextView focusableTarget = (TextView) findViewById(R.id.focusable_target);
+        focusableButton.setOnClickListener(v -> focusableTarget.setFocusable(true));
+
+        Button focusedButton = (Button) findViewById(R.id.focused_button);
+        TextView focusedTarget = (TextView) findViewById(R.id.focused_target);
+        focusedButton.setOnClickListener(v -> focusedTarget.requestFocus());
+
+        Button longClickableButton = (Button) findViewById(R.id.long_clickable_button);
+        TextView longClickableTarget = (TextView) findViewById(R.id.long_clickable_target);
+        longClickableButton.setOnClickListener(v -> longClickableTarget.setLongClickable(true));
+
+        Button scrollableButton = (Button) findViewById(R.id.scrollable_button);
+        HorizontalScrollView scrollableTarget = (HorizontalScrollView) findViewById(
+                R.id.scrollable_target);
+        scrollableButton.setOnClickListener(v -> {
+            scrollableTarget.getLayoutParams().width = 1; // Force horizontal scrollbar.
+            scrollableTarget.requestLayout();
+        });
+
+        Button selectedButton = (Button) findViewById(R.id.selected_button);
+        TextView selectedTarget = (TextView) findViewById(R.id.selected_target);
+        selectedButton.setOnClickListener(v -> selectedTarget.setSelected(true));
+
+        Button descButton = (Button) findViewById(R.id.desc_button);
+        TextView descTarget = (TextView) findViewById(R.id.desc_target);
+        descButton.setOnClickListener(v -> descTarget.setContentDescription("updated_desc"));
+
+        Button textButton = (Button) findViewById(R.id.text_button);
+        TextView textTarget = (TextView) findViewById(R.id.text_target);
+        textButton.setOnClickListener(v -> textTarget.setText("updated_text"));
+    }
+}
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testclazz_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testclazz_activity.xml
index 980c9b3..4727954 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testclazz_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testclazz_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,59 +14,70 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".BySelectorTestClazzActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".BySelectorTestClazzActivity">
 
-    <Button android:id="@+id/button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Button Instance" />
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Button Instance" />
 
-    <CheckBox android:id="@+id/check_box"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="CheckBox Instance" />
+    <CheckBox
+        android:id="@+id/check_box"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="CheckBox Instance" />
 
-    <EditText android:id="@+id/edit_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="EditText Instance" />
+    <EditText
+        android:id="@+id/edit_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="EditText Instance" />
 
-    <ProgressBar android:id="@+id/progress_bar"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
+    <ProgressBar
+        android:id="@+id/progress_bar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
 
-    <RadioButton android:id="@+id/radio_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="RadioButton Instance" />
+    <RadioButton
+        android:id="@+id/radio_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="RadioButton Instance" />
 
-    <RatingBar android:id="@+id/rating_bar"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
+    <RatingBar
+        android:id="@+id/rating_bar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
 
-    <SeekBar android:id="@+id/seek_bar"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
+    <SeekBar
+        android:id="@+id/seek_bar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
 
-    <Switch android:id="@+id/switch_toggle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
+    <Switch
+        android:id="@+id/switch_toggle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
 
-    <TextClock android:id="@+id/text_clock"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
+    <TextClock
+        android:id="@+id/text_clock"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
 
-    <TextView android:id="@+id/text_view"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="TextView Instance" />
+    <TextView
+        android:id="@+id/text_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="TextView Instance" />
 
-    <ToggleButton android:id="@+id/toggle_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
+    <ToggleButton
+        android:id="@+id/toggle_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
 
 </LinearLayout>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testdesc_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testdesc_activity.xml
index c09010f..8cd1eb3 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testdesc_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testdesc_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,19 +14,21 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".BySelectorTestDescActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".BySelectorTestDescActivity">
 
-    <Button android:id="@+id/button_with_layout_description"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:contentDescription="Content Description Set From Layout" />
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:contentDescription="This button desc contains some text." />
 
-    <Button android:id="@+id/button_with_runtime_description"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
+    <RatingBar
+        android:id="@+id/rating_bar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
 
 </LinearLayout>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testhaschild_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testhaschild_activity.xml
index 2451c41..5c6efd8 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testhaschild_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testhaschild_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,57 +14,65 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".BySelectorTestClazzActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".BySelectorTestClazzActivity">
 
-    <LinearLayout android:id="@+id/toplevel1"
+    <LinearLayout
+        android:id="@+id/toplevel1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/toplevel1_child1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Top-Level1 Child1" />
+
+    </LinearLayout>
+
+
+    <LinearLayout
+        android:id="@+id/toplevel2"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/toplevel2_child1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Top-Level2 Child1" />
+
+        <TextView
+            android:id="@+id/toplevel2_child2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Top-Level2 Child2" />
+
+    </LinearLayout>
+
+
+    <RelativeLayout
+        android:id="@+id/toplevel3"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/toplevel3_container1"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:orientation="vertical">
 
-        <TextView android:id="@+id/toplevel1_child1"
+            <TextView
+                android:id="@+id/toplevel3_container1_child1"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:text="Top-Level1 Child1" />
-
-    </LinearLayout>
-
-
-    <LinearLayout android:id="@+id/toplevel2"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical">
-
-            <TextView android:id="@+id/toplevel2_child1"
-                  android:layout_width="wrap_content"
-                  android:layout_height="wrap_content"
-                  android:text="Top-Level2 Child1" />
-
-            <TextView android:id="@+id/toplevel2_child2"
-                  android:layout_width="wrap_content"
-                  android:layout_height="wrap_content"
-                  android:text="Top-Level2 Child2" />
-
-    </LinearLayout>
-
-
-    <RelativeLayout android:id="@+id/toplevel3"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical">
-
-        <LinearLayout android:id="@+id/toplevel3_container1"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"
-                android:orientation="vertical">
-
-            <TextView android:id="@+id/toplevel3_container1_child1"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="Top-Level3, Container 1, Child 1" />
+                android:text="Top-Level3, Container 1, Child 1" />
 
         </LinearLayout>
 
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testres_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testres_activity.xml
index 2026ba5..3bf4614 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testres_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testres_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,25 +14,28 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".BySelectorTestResActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".BySelectorTestResActivity">
 
-    <TextView android:id="@+id/unique_id"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Unique ID" />
+    <TextView
+        android:id="@+id/unique_id"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Unique ID" />
 
-    <TextView android:id="@+id/shared_id"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Shared ID Instance 1" />
+    <TextView
+        android:id="@+id/shared_id"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Shared ID Instance 1" />
 
-    <TextView android:id="@+id/shared_id"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Shared ID Instance 2" />
+    <TextView
+        android:id="@+id/shared_id"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Shared ID Instance 2" />
 
 </LinearLayout>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testtext_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testtext_activity.xml
index c94a8e74..d625c0c 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testtext_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/byselector_testtext_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,25 +14,28 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".BySelectorTestTextActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".BySelectorTestTextActivity">
 
-    <TextView android:id="@+id/unique_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Unique Text" />
+    <TextView
+        android:id="@+id/unique_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Unique Text" />
 
-    <TextView android:id="@+id/common_text1"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Common Text" />
+    <TextView
+        android:id="@+id/common_text1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Common Text" />
 
-    <TextView android:id="@+id/common_text2"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Common Text" />
+    <TextView
+        android:id="@+id/common_text2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Common Text" />
 
 </LinearLayout>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/main_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/main_activity.xml
index 4edf9d7..83eea3a 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/main_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/main_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,65 +14,71 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".MainActivity" >
-
-    <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Text View 1" />
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".MainActivity">
 
     <Button
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:contentDescription="I'm accessible!"
-            android:text="Accessible button" />
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:contentDescription="I'm accessible!"
+        android:text="Accessible button" />
 
-    <TextView android:id="@+id/example_id"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="TextView with an id" />
+    <LinearLayout
+        android:id="@+id/nested_elements"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
 
-    <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Sample text" />
-
-    <ListView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:entries="@array/list_view_entries" >
-    </ListView>
-
-    <LinearLayout android:id="@+id/nested_elements"
+        <LinearLayout
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:orientation="vertical">
-        <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="First Level" />
-        <LinearLayout
+
+            <LinearLayout
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
                 android:orientation="vertical">
-            <TextView
+
+                <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="Second Level" />
-            <LinearLayout
-                    android:layout_width="fill_parent"
-                    android:layout_height="wrap_content"
-                    android:orientation="vertical">
-                <TextView
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:text="Third Level" />
+                    android:text="Third Level" />
             </LinearLayout>
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Second Level" />
         </LinearLayout>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="First Level" />
     </LinearLayout>
 
+    <ListView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:entries="@array/list_view_entries"></ListView>
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Sample text" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Text View 1" />
+
+    <TextView
+        android:id="@+id/example_id"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="TextView with an id" />
+
 </LinearLayout>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testcleartext_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testcleartext_activity.xml
index 191b446..49df9a2 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testcleartext_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testcleartext_activity.xml
@@ -15,16 +15,17 @@
   -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".UiObject2TestClearTextActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".UiObject2TestClearTextActivity">
 
     <EditText
-            android:id="@+id/edit_text"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:inputType="text"
-            android:text="sample_text" />
+        android:id="@+id/edit_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:inputType="text"
+        android:text="sample_text" />
+
 </LinearLayout>
\ No newline at end of file
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclick_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclick_activity.xml
index 0ed66eb..c725b6f 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclick_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclick_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,21 +14,23 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".UiObject2TestClickActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".UiObject2TestClickActivity">
 
-    <Button android:id="@+id/button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Click Me!"
-            android:onClick="onButtonClick" />
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="onButtonClick"
+        android:text="Click Me!" />
 
-    <CheckBox android:id="@+id/check_box"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:checked="false" />
+    <CheckBox
+        android:id="@+id/check_box"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:checked="false" />
 
 </LinearLayout>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclickandwait_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclickandwait_activity.xml
index de65a1a..d9c8163 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclickandwait_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclickandwait_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,15 +14,16 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".UiObject2TestClickAndWaitActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".UiObject2TestClickAndWaitActivity">
 
-        <Button android:id="@+id/new_window_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:onClick="launchNewWindow" />
+    <Button
+        android:id="@+id/new_window_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="launchNewWindow" />
 
 </LinearLayout>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclickandwaitconfirm_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclickandwaitconfirm_activity.xml
index 505c17d2..1e7d3e0 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclickandwaitconfirm_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testclickandwaitconfirm_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,15 +14,16 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".UiObject2TestClickAndWaitConfirmActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".UiObject2TestClickAndWaitConfirmActivity">
 
-        <TextView android:id="@+id/confirm_text"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="confirm" />
+    <TextView
+        android:id="@+id/confirm_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="confirm" />
 
 </LinearLayout>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testisenabled_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testisenabled_activity.xml
new file mode 100644
index 0000000..4db7bac
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testisenabled_activity.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".UiObject2TestIsEnabledActivity">
+
+    <TextView
+        android:id="@+id/disabled_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:enabled="false"
+        android:text="Disabled Text View" />
+
+    <TextView
+        android:id="@+id/enabled_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:enabled="true"
+        android:text="Enabled Text View" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testisfocused_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testisfocused_activity.xml
new file mode 100644
index 0000000..5fd9105
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testisfocused_activity.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:focusable="true"
+    android:focusableInTouchMode="true"
+    android:orientation="vertical"
+    tools:context=".UiObject2TestIsFocusedActivity">
+
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="button" />
+
+    <TextView
+        android:id="@+id/focusable_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        android:text="focusable_text_view" />
+
+    <TextView
+        android:id="@+id/non_focusable_text_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:focusable="false"
+        android:focusableInTouchMode="false"
+        android:text="non_focusable_text_view" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testislongclickable_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testislongclickable_activity.xml
new file mode 100644
index 0000000..99cd6e7
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testislongclickable_activity.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (C) 2014 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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".UiObject2TestIsLongClickableActivity">
+
+    <Button
+        android:id="@+id/long_clickable_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:longClickable="true"
+        android:text="long_clickable_button" />
+
+    <Button
+        android:id="@+id/non_long_clickable_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="non_long_clickable_button" />
+
+</LinearLayout>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testisselected_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testisselected_activity.xml
new file mode 100644
index 0000000..67ba8b4
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testisselected_activity.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".UiObject2TestIsSelectedActivity">
+
+    <Button
+        android:id="@+id/selected_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="selected_button" />
+
+    <TextView
+        android:id="@+id/selected_target"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="selected_target" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testlongclick_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testlongclick_activity.xml
index 9b1286ba..0e77eb2 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testlongclick_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testlongclick_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,15 +14,16 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".UiObject2TestLongClickActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".UiObject2TestLongClickActivity">
 
-    <Button android:id="@+id/button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="Long Click Me!" />
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Long Click Me!" />
 
 </LinearLayout>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testpinch_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testpinch_activity.xml
index 4698d2c..5f1ecbd 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testpinch_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testpinch_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,24 +14,26 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".UiObject2TestPinchActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".UiObject2TestPinchActivity">
 
-    <LinearLayout android:id="@+id/pinch_area"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"
-            android:layout_margin="30dp"
-            android:background="@android:color/white">
+    <LinearLayout
+        android:id="@+id/pinch_area"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:layout_margin="30dp"
+        android:background="@android:color/white">
 
-            <TextView android:id="@+id/scale_factor"
-                android:layout_width="27mm"
-                android:layout_height="wrap_content"
-                android:textColor="@android:color/white"
-                android:background="@android:color/black"
-                android:text="1.0f" />
+        <TextView
+            android:id="@+id/scale_factor"
+            android:layout_width="27mm"
+            android:layout_height="wrap_content"
+            android:background="@android:color/black"
+            android:text="1.0f"
+            android:textColor="@android:color/white" />
 
     </LinearLayout>
 
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testverticalscroll_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testverticalscroll_activity.xml
index 1a2ddb8..596267f1 100644
--- a/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testverticalscroll_activity.xml
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/uiobject2_testverticalscroll_activity.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
  * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,60 +14,67 @@
  * limitations under the License.
  -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        tools:context=".UiObject2TestVerticalScrollActivity">
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".UiObject2TestVerticalScrollActivity">
 
-        <TextView android:id="@+id/fling_detected"
+    <ScrollView
+        android:id="@+id/scroll_view"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+
+        <RelativeLayout
+            android:layout_width="fill_parent"
+            android:layout_height="20000px">
+
+            <TextView
+                android:id="@+id/top_text"
+                android:layout_width="wrap_content"
+                android:layout_height="50px"
+                android:layout_alignParentTop="true"
+                android:text="This is the top" />
+
+            <TextView
+                android:id="@+id/from_top_5000"
+                android:layout_width="wrap_content"
+                android:layout_height="50px"
+                android:layout_alignParentTop="true"
+                android:layout_marginTop="5000px"
+                android:text="This is 5000px from the top" />
+
+            <TextView
+                android:id="@+id/from_top_10000"
+                android:layout_width="wrap_content"
+                android:layout_height="50px"
+                android:layout_alignParentTop="true"
+                android:layout_marginTop="10000px"
+                android:text="This is 10000px from the top" />
+
+            <TextView
+                android:id="@+id/from_top_15000"
+                android:layout_width="wrap_content"
+                android:layout_height="50px"
+                android:layout_alignParentTop="true"
+                android:layout_marginTop="15000px"
+                android:text="This is 15000px from the top" />
+
+            <TextView
+                android:id="@+id/bottom_text"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:text="false" />
+                android:layout_alignParentBottom="true"
+                android:text="This is the bottom" />
 
-        <ScrollView android:id="@+id/scroll_view"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content">
+        </RelativeLayout>
 
-            <RelativeLayout
-                    android:layout_width="fill_parent"
-                    android:layout_height="20000px">
+    </ScrollView>
 
-                <TextView android:id="@+id/top_text"
-                        android:layout_width="wrap_content"
-                        android:layout_height="50px"
-                        android:layout_alignParentTop="true"
-                        android:text="This is the top" />
-
-                <TextView android:id="@+id/from_top_5000"
-                        android:layout_width="wrap_content"
-                        android:layout_height="50px"
-                        android:layout_alignParentTop="true"
-                        android:layout_marginTop="5000px"
-                        android:text="This is 5000px from the top" />
-
-                <TextView android:id="@+id/from_top_10000"
-                        android:layout_width="wrap_content"
-                        android:layout_height="50px"
-                        android:layout_alignParentTop="true"
-                        android:layout_marginTop="10000px"
-                        android:text="This is 10000px from the top" />
-
-                <TextView android:id="@+id/from_top_15000"
-                        android:layout_width="wrap_content"
-                        android:layout_height="50px"
-                        android:layout_alignParentTop="true"
-                        android:layout_marginTop="15000px"
-                        android:text="This is 15000px from the top" />
-
-                <TextView android:id="@+id/bottom_text"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_alignParentBottom="true"
-                        android:text="This is the bottom" />
-
-            </RelativeLayout>
-
-        </ScrollView>
+    <TextView
+        android:id="@+id/fling_detected"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="false" />
 
 </LinearLayout>
diff --git a/test/uiautomator/integration-tests/testapp/src/main/res/layout/until_test_activity.xml b/test/uiautomator/integration-tests/testapp/src/main/res/layout/until_test_activity.xml
new file mode 100644
index 0000000..7001fdd
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/main/res/layout/until_test_activity.xml
@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * 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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:focusable="true"
+    android:focusableInTouchMode="true"
+    android:orientation="vertical"
+    tools:context=".UntilTestActivity">
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/gone_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Gone" />
+
+        <TextView
+            android:id="@+id/gone_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="gone_target"
+            android:visibility="visible" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/find_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Find" />
+
+        <TextView
+            android:id="@+id/find_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="find_target"
+            android:visibility="gone" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/checked_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Checked" />
+
+        <CheckBox
+            android:id="@+id/checked_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:checked="false"
+            android:text="checked_target" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/clickable_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Clickable" />
+
+        <TextView
+            android:id="@+id/clickable_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:clickable="false"
+            android:text="clickable_target" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/enabled_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Enabled" />
+
+        <TextView
+            android:id="@+id/enabled_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:enabled="false"
+            android:text="enabled_target" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/focusable_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Focusable" />
+
+        <TextView
+            android:id="@+id/focusable_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:focusable="false"
+            android:text="focusable_target" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/focused_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Focused" />
+
+        <TextView
+            android:id="@+id/focused_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:focusable="true"
+            android:focusableInTouchMode="true"
+            android:text="focused_target" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/long_clickable_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="LongClickable" />
+
+        <TextView
+            android:id="@+id/long_clickable_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:longClickable="false"
+            android:text="long_clickable_target" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/scrollable_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Scrollable" />
+
+        <HorizontalScrollView
+            android:id="@+id/scrollable_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="scrollable_target" />
+        </HorizontalScrollView>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/selected_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Selected" />
+
+        <TextView
+            android:id="@+id/selected_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="selected_target" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/desc_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Desc" />
+
+        <TextView
+            android:id="@+id/desc_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:contentDescription="initial_desc"
+            android:text="desc_target" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/text_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Text" />
+
+        <TextView
+            android:id="@+id/text_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="initial_text" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/test/uiautomator/uiautomator/lint-baseline.xml b/test/uiautomator/uiautomator/lint-baseline.xml
index eddc27b..2b0f7fdfb 100644
--- a/test/uiautomator/uiautomator/lint-baseline.xml
+++ b/test/uiautomator/uiautomator/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha01" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha01)" variant="all" version="7.4.0-alpha01">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
@@ -75,42 +75,6 @@
 
     <issue
         id="NewApi"
-        message="Call requires API level 24 (current min is 18): `android.app.Instrumentation#getUiAutomation`"
-        errorLine1="        doReturn(automation).when(mockInstrumentation).getUiAutomation(anyInt());"
-        errorLine2="                                                       ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/UiDeviceTests.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 24 (current min is 18): `android.app.Instrumentation#getUiAutomation`"
-        errorLine1="            Mockito.verify(mockInstrumentation, atLeastOnce()).getUiAutomation(eq(defaultFlags));"
-        errorLine2="                                                               ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/UiDeviceTests.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 24 (current min is 18): `android.app.Instrumentation#getUiAutomation`"
-        errorLine1="        doReturn(automation).when(mockInstrumentation).getUiAutomation(anyInt());"
-        errorLine2="                                                       ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/UiDeviceTests.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 24 (current min is 18): `android.app.Instrumentation#getUiAutomation`"
-        errorLine1="            Mockito.verify(mockInstrumentation, atLeastOnce()).getUiAutomation(eq(flags));"
-        errorLine2="                                                               ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/UiDeviceTests.java"/>
-    </issue>
-
-    <issue
-        id="NewApi"
         message="Call requires API level 23 (current min is 18): `android.content.Context#getSystemService`"
         errorLine1="            mDevice.getInstrumentation().getContext().getSystemService(DisplayManager.class);"
         errorLine2="                                                      ~~~~~~~~~~~~~~~~">
@@ -328,24 +292,6 @@
     <issue
         id="PrivateConstructorForUtilityClass"
         message="Utility class is missing private constructor"
-        errorLine1="class AccessibilityNodeInfoDumper {"
-        errorLine2="      ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/AccessibilityNodeInfoDumper.java"/>
-    </issue>
-
-    <issue
-        id="PrivateConstructorForUtilityClass"
-        message="Utility class is missing private constructor"
-        errorLine1="class AccessibilityNodeInfoHelper {"
-        errorLine2="      ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/AccessibilityNodeInfoHelper.java"/>
-    </issue>
-
-    <issue
-        id="PrivateConstructorForUtilityClass"
-        message="Utility class is missing private constructor"
         errorLine1="public class Until {"
         errorLine2="             ~~~~~">
         <location
@@ -634,1158 +580,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector copy(BySelector original) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector copy(BySelector original) {"
-        errorLine2="                                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector clazz(String className) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector clazz(String className) {"
-        errorLine2="                                   ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector clazz(String packageName, String className) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector clazz(String packageName, String className) {"
-        errorLine2="                                   ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector clazz(String packageName, String className) {"
-        errorLine2="                                                       ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector clazz(Class clazz) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector clazz(Class clazz) {"
-        errorLine2="                                   ~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector clazz(Pattern className) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector clazz(Pattern className) {"
-        errorLine2="                                   ~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector desc(String contentDescription) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector desc(String contentDescription) {"
-        errorLine2="                                  ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector descContains(String substring) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector descContains(String substring) {"
-        errorLine2="                                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector descStartsWith(String substring) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector descStartsWith(String substring) {"
-        errorLine2="                                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector descEndsWith(String substring) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector descEndsWith(String substring) {"
-        errorLine2="                                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector desc(Pattern contentDescription) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector desc(Pattern contentDescription) {"
-        errorLine2="                                  ~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector pkg(String applicationPackage) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector pkg(String applicationPackage) {"
-        errorLine2="                                 ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector pkg(Pattern applicationPackage) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector pkg(Pattern applicationPackage) {"
-        errorLine2="                                 ~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector res(String resourceName) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector res(String resourceName) {"
-        errorLine2="                                 ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector res(String resourcePackage, String resourceId) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector res(String resourcePackage, String resourceId) {"
-        errorLine2="                                 ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector res(String resourcePackage, String resourceId) {"
-        errorLine2="                                                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector res(Pattern resourceName) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector res(Pattern resourceName) {"
-        errorLine2="                                 ~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector text(String text) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector text(String text) {"
-        errorLine2="                                  ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector textContains(String substring) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector textContains(String substring) {"
-        errorLine2="                                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector textStartsWith(String substring) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector textStartsWith(String substring) {"
-        errorLine2="                                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector textEndsWith(String substring) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector textEndsWith(String substring) {"
-        errorLine2="                                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector text(Pattern regex) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector text(Pattern regex) {"
-        errorLine2="                                  ~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector checkable(boolean isCheckable) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector checked(boolean isChecked) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector clickable(boolean isClickable) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector enabled(boolean isEnabled) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector focusable(boolean isFocusable) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector focused(boolean isFocused) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector longClickable(boolean isLongClickable) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector scrollable(boolean isScrollable) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector selected(boolean isSelected) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector depth(int depth) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector hasChild(BySelector childSelector) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector hasChild(BySelector childSelector) {"
-        errorLine2="                                      ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector hasDescendant(BySelector descendantSelector) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector hasDescendant(BySelector descendantSelector) {"
-        errorLine2="                                           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector hasDescendant(BySelector descendantSelector, int maxDepth) {"
-        errorLine2="                  ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static BySelector hasDescendant(BySelector descendantSelector, int maxDepth) {"
-        errorLine2="                                           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/By.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector clazz(String className) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector clazz(String className) {"
-        errorLine2="                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector clazz(String packageName, String className) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector clazz(String packageName, String className) {"
-        errorLine2="                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector clazz(String packageName, String className) {"
-        errorLine2="                                                ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector clazz(Class clazz) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector clazz(Class clazz) {"
-        errorLine2="                            ~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector clazz(Pattern className) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector clazz(Pattern className) {"
-        errorLine2="                            ~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector desc(String contentDescription) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector desc(String contentDescription) {"
-        errorLine2="                           ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector descContains(String substring) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector descContains(String substring) {"
-        errorLine2="                                   ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector descStartsWith(String substring) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector descStartsWith(String substring) {"
-        errorLine2="                                     ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector descEndsWith(String substring) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector descEndsWith(String substring) {"
-        errorLine2="                                   ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector desc(Pattern contentDescription) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector desc(Pattern contentDescription) {"
-        errorLine2="                           ~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector pkg(String applicationPackage) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector pkg(String applicationPackage) {"
-        errorLine2="                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector pkg(Pattern applicationPackage) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector pkg(Pattern applicationPackage) {"
-        errorLine2="                          ~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector res(String resourceName) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector res(String resourceName) {"
-        errorLine2="                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector res(String resourcePackage, String resourceId) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector res(String resourcePackage, String resourceId) {"
-        errorLine2="                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector res(String resourcePackage, String resourceId) {"
-        errorLine2="                                                  ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector res(Pattern resourceName) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector res(Pattern resourceName) {"
-        errorLine2="                          ~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector text(String textValue) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector text(String textValue) {"
-        errorLine2="                           ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector textContains(String substring) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector textContains(String substring) {"
-        errorLine2="                                   ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector textStartsWith(String substring) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector textStartsWith(String substring) {"
-        errorLine2="                                     ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector textEndsWith(String substring) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector textEndsWith(String substring) {"
-        errorLine2="                                   ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector text(Pattern textValue) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector text(Pattern textValue) {"
-        errorLine2="                           ~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector checkable(boolean isCheckable) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector checked(boolean isChecked) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector clickable(boolean isClickable) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector enabled(boolean isEnabled) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector focusable(boolean isFocusable) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector focused(boolean isFocused) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector longClickable(boolean isLongClickable) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector scrollable(boolean isScrollable) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector selected(boolean isSelected) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector depth(int exactDepth) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector depth(int min, int max) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector minDepth(int min) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector maxDepth(int max) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector hasChild(BySelector childSelector) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector hasChild(BySelector childSelector) {"
-        errorLine2="                               ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector hasDescendant(BySelector descendantSelector) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector hasDescendant(BySelector descendantSelector) {"
-        errorLine2="                                    ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector hasDescendant(BySelector descendantSelector, int maxDepth) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public BySelector hasDescendant(BySelector descendantSelector, int maxDepth) {"
-        errorLine2="                                    ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/BySelector.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static Configurator getInstance() {"
-        errorLine2="                  ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/Configurator.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Configurator setWaitForIdleTimeout(long timeout) {"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/Configurator.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Configurator setWaitForSelectorTimeout(long timeout) {"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/Configurator.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Configurator setScrollAcknowledgmentTimeout(long timeout) {"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/Configurator.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Configurator setActionAcknowledgmentTimeout(long timeout) {"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/Configurator.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Configurator setKeyInjectionDelay(long delay) {"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/Configurator.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Configurator setToolType(final int toolType) {"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/Configurator.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Configurator setUiAutomationFlags(int flags) {"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/Configurator.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static Direction reverse(Direction direction) {"
-        errorLine2="                  ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/Direction.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static Direction reverse(Direction direction) {"
-        errorLine2="                                    ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/Direction.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void sendStatus(int resultCode, Bundle status);"
-        errorLine2="                                           ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/IAutomationSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    public static Tracer getInstance() {"
         errorLine2="                  ~~~~~~">
         <location
@@ -1840,96 +634,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiCollection(UiSelector selector) {"
-        errorLine2="                        ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiCollection.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByDescription(UiSelector childPattern, String text)"
-        errorLine2="           ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiCollection.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByDescription(UiSelector childPattern, String text)"
-        errorLine2="                                          ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiCollection.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByDescription(UiSelector childPattern, String text)"
-        errorLine2="                                                                   ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiCollection.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByInstance(UiSelector childPattern, int instance)"
-        errorLine2="           ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiCollection.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByInstance(UiSelector childPattern, int instance)"
-        errorLine2="                                       ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiCollection.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByText(UiSelector childPattern, String text)"
-        errorLine2="           ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiCollection.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByText(UiSelector childPattern, String text)"
-        errorLine2="                                   ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiCollection.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByText(UiSelector childPattern, String text)"
-        errorLine2="                                                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiCollection.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public int getChildCount(UiSelector childPattern) {"
-        errorLine2="                             ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiCollection.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    public UiObject findObject(UiSelector selector) {"
         errorLine2="           ~~~~~~~~">
         <location
@@ -2650,42 +1354,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObjectNotFoundException(String msg) {"
-        errorLine2="                                     ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiObjectNotFoundException.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObjectNotFoundException(String detailMessage, Throwable throwable) {"
-        errorLine2="                                     ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiObjectNotFoundException.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObjectNotFoundException(String detailMessage, Throwable throwable) {"
-        errorLine2="                                                           ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiObjectNotFoundException.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObjectNotFoundException(Throwable throwable) {"
-        errorLine2="                                     ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiObjectNotFoundException.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    public UiScrollable(UiSelector container) {"
         errorLine2="                        ~~~~~~~~~~">
         <location
@@ -2722,33 +1390,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByDescription(UiSelector childPattern, String text)"
-        errorLine2="           ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiScrollable.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByDescription(UiSelector childPattern, String text)"
-        errorLine2="                                          ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiScrollable.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByDescription(UiSelector childPattern, String text)"
-        errorLine2="                                                                   ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiScrollable.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    public UiObject getChildByDescription(UiSelector childPattern, String text,"
         errorLine2="           ~~~~~~~~">
         <location
@@ -2777,15 +1418,6 @@
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    public UiObject getChildByInstance(UiSelector childPattern, int instance)"
-        errorLine2="           ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiScrollable.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByInstance(UiSelector childPattern, int instance)"
         errorLine2="                                       ~~~~~~~~~~">
         <location
             file="src/main/java/androidx/test/uiautomator/UiScrollable.java"/>
@@ -2794,33 +1426,6 @@
     <issue
         id="UnknownNullness"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByText(UiSelector childPattern, String text)"
-        errorLine2="           ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiScrollable.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByText(UiSelector childPattern, String text)"
-        errorLine2="                                   ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiScrollable.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public UiObject getChildByText(UiSelector childPattern, String text)"
-        errorLine2="                                                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/test/uiautomator/UiScrollable.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
         errorLine1="    public UiObject getChildByText(UiSelector childPattern, String text, boolean allowScrollSearch)"
         errorLine2="           ~~~~~~~~">
         <location
diff --git a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/ByMatcher.java b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/ByMatcher.java
index a17297c..0e44a89 100644
--- a/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/ByMatcher.java
+++ b/test/uiautomator/uiautomator/src/main/java/androidx/test/uiautomator/ByMatcher.java
@@ -202,7 +202,7 @@
     }
 
     /** Helper method used to evaluate a {@link Pattern} criteria if it is set. */
-    static private boolean checkCriteria(Pattern criteria, CharSequence value) {
+    static boolean checkCriteria(Pattern criteria, CharSequence value) {
         if (criteria == null) {
             return true;
         }
@@ -210,7 +210,7 @@
     }
 
     /** Helper method used to evaluate a {@link Boolean} criteria if it is set. */
-    static private boolean checkCriteria(Boolean criteria, boolean value) {
+    static boolean checkCriteria(Boolean criteria, boolean value) {
         if (criteria == null) {
             return true;
         }
@@ -348,7 +348,7 @@
      */
     private static class SinglyLinkedList<T> implements Iterable<T> {
 
-        private final Node<T> mHead;
+        final Node<T> mHead;
 
         /** Constructs an empty list. */
         public SinglyLinkedList() {
diff --git a/testutils/testutils-datastore/OWNERS b/testutils/testutils-datastore/OWNERS
new file mode 100644
index 0000000..e750dab
--- /dev/null
+++ b/testutils/testutils-datastore/OWNERS
@@ -0,0 +1,3 @@
[email protected]
[email protected]
[email protected]
diff --git a/testutils/testutils-datastore/build.gradle b/testutils/testutils-datastore/build.gradle
new file mode 100644
index 0000000..6582467
--- /dev/null
+++ b/testutils/testutils-datastore/build.gradle
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+    id("AndroidXPlugin")
+    id("kotlin")
+}
+
+dependencies {
+    implementation(libs.kotlinStdlib)
+}
+
+androidx {
+    type = LibraryType.INTERNAL_TEST_LIBRARY
+}
diff --git a/text/text/build.gradle b/text/text/build.gradle
index 231df11..331866c 100644
--- a/text/text/build.gradle
+++ b/text/text/build.gradle
@@ -25,6 +25,7 @@
 
 dependencies {
     implementation(libs.kotlinStdlib)
+    implementation("androidx.core:core:1.7.0")
 
     api "androidx.annotation:annotation:1.2.0"
 
@@ -32,7 +33,6 @@
     testImplementation(libs.testRunner)
     testImplementation(libs.junit)
 
-    androidTestImplementation("androidx.core:core:1.5.0-rc02")
     androidTestImplementation(project(":compose:ui:ui-test-font"))
     androidTestImplementation(libs.testRules)
     androidTestImplementation(libs.testRunner)
diff --git a/text/text/lint-baseline.xml b/text/text/lint-baseline.xml
index d7dfff3..c5957fa 100644
--- a/text/text/lint-baseline.xml
+++ b/text/text/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha01" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha01)" variant="all" version="7.4.0-alpha01">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="BanInlineOptIn"
diff --git a/tracing/tracing-perfetto-binary/api/current.txt b/tracing/tracing-perfetto-binary/api/current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/tracing/tracing-perfetto-binary/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/tracing/tracing-perfetto-binary/api/public_plus_experimental_current.txt b/tracing/tracing-perfetto-binary/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/tracing/tracing-perfetto-binary/api/public_plus_experimental_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/development/gradleRemoteCache/data/.empty b/tracing/tracing-perfetto-binary/api/res-current.txt
similarity index 100%
copy from development/gradleRemoteCache/data/.empty
copy to tracing/tracing-perfetto-binary/api/res-current.txt
diff --git a/tracing/tracing-perfetto-binary/api/restricted_current.txt b/tracing/tracing-perfetto-binary/api/restricted_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/tracing/tracing-perfetto-binary/api/restricted_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/tracing/tracing-perfetto-binary/build.gradle b/tracing/tracing-perfetto-binary/build.gradle
index cf69010..11f4655 100644
--- a/tracing/tracing-perfetto-binary/build.gradle
+++ b/tracing/tracing-perfetto-binary/build.gradle
@@ -82,7 +82,7 @@
 
 androidx {
     name = "AndroidX Tracing: Perfetto SDK Native Dependencies"
-    publish = Publish.SNAPSHOT_ONLY
+    publish = Publish.SNAPSHOT_AND_RELEASE
     mavenVersion = LibraryVersions.TRACING_PERFETTO
     mavenGroup = LibraryGroups.TRACING
     inceptionYear = "2022"
diff --git a/tracing/tracing-perfetto/api/current.txt b/tracing/tracing-perfetto/api/current.txt
new file mode 100644
index 0000000..4d8a122
--- /dev/null
+++ b/tracing/tracing-perfetto/api/current.txt
@@ -0,0 +1,13 @@
+// Signature format: 4.0
+package androidx.tracing.perfetto {
+
+  public final class Tracing {
+    method public boolean isEnabled();
+    method public void traceEventEnd();
+    method public void traceEventStart(int key, String traceInfo);
+    property public final boolean isEnabled;
+    field public static final androidx.tracing.perfetto.Tracing INSTANCE;
+  }
+
+}
+
diff --git a/tracing/tracing-perfetto/api/public_plus_experimental_current.txt b/tracing/tracing-perfetto/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..4d8a122
--- /dev/null
+++ b/tracing/tracing-perfetto/api/public_plus_experimental_current.txt
@@ -0,0 +1,13 @@
+// Signature format: 4.0
+package androidx.tracing.perfetto {
+
+  public final class Tracing {
+    method public boolean isEnabled();
+    method public void traceEventEnd();
+    method public void traceEventStart(int key, String traceInfo);
+    property public final boolean isEnabled;
+    field public static final androidx.tracing.perfetto.Tracing INSTANCE;
+  }
+
+}
+
diff --git a/development/gradleRemoteCache/data/.empty b/tracing/tracing-perfetto/api/res-current.txt
similarity index 100%
copy from development/gradleRemoteCache/data/.empty
copy to tracing/tracing-perfetto/api/res-current.txt
diff --git a/tracing/tracing-perfetto/api/restricted_current.txt b/tracing/tracing-perfetto/api/restricted_current.txt
new file mode 100644
index 0000000..4d8a122
--- /dev/null
+++ b/tracing/tracing-perfetto/api/restricted_current.txt
@@ -0,0 +1,13 @@
+// Signature format: 4.0
+package androidx.tracing.perfetto {
+
+  public final class Tracing {
+    method public boolean isEnabled();
+    method public void traceEventEnd();
+    method public void traceEventStart(int key, String traceInfo);
+    property public final boolean isEnabled;
+    field public static final androidx.tracing.perfetto.Tracing INSTANCE;
+  }
+
+}
+
diff --git a/tracing/tracing-perfetto/build.gradle b/tracing/tracing-perfetto/build.gradle
index 785940a..d2296db 100644
--- a/tracing/tracing-perfetto/build.gradle
+++ b/tracing/tracing-perfetto/build.gradle
@@ -34,7 +34,6 @@
 
 androidx {
     name = "AndroidX Tracing: Perfetto SDK"
-    runApiTasks= new RunApiTasks.No("The API is still evolving")
     publish = Publish.SNAPSHOT_AND_RELEASE
     mavenVersion = LibraryVersions.TRACING_PERFETTO
     mavenGroup = LibraryGroups.TRACING
diff --git a/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/test/TracingTest.kt b/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/test/TracingTest.kt
index 05d31ff..09312f3 100644
--- a/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/test/TracingTest.kt
+++ b/tracing/tracing-perfetto/src/androidTest/java/androidx/tracing/perfetto/test/TracingTest.kt
@@ -50,4 +50,4 @@
 
         // TODO(214562374): verify the content by getting it back from Perfetto
     }
-}
\ No newline at end of file
+}
diff --git a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/Tracing.kt b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/Tracing.kt
index 453fcc0..6a4b453 100644
--- a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/Tracing.kt
+++ b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/Tracing.kt
@@ -40,13 +40,12 @@
 
 object Tracing {
     /**
-     * Indicates that the tracing library has been loaded and that the app was registered with
-     * Perfetto as a data source.
-     *
-     * Note: some of class' code relies on the field ever changing from true -> false and not in
-     * the other direction, which is realistic (we cannot unload the library or unregister with
-     * Perfetto at the time of writing).
+     * Indicates whether the tracing library has been loaded and the app registered with
+     * Perfetto SDK.
      */
+    // Note: some of class' code relies on the field never changing from true -> false,
+    // which is realistic (at the time of writing this, we are unable to unload the library and
+    // unregister the app with Perfetto).
     var isEnabled: Boolean = false
         private set
 
@@ -59,7 +58,7 @@
     private val enableTracingLock = ReentrantReadWriteLock()
 
     @RequiresApi(Build.VERSION_CODES.R) // TODO(234351579): Support API < 30
-    fun enable() = enable(null)
+    internal fun enable() = enable(null)
 
     @RequiresApi(Build.VERSION_CODES.R) // TODO(234351579): Support API < 30
     internal fun enable(file: File, context: Context) = enable(file to context)
@@ -95,17 +94,17 @@
                 is IncorrectChecksumException, is UnapprovedLocationException ->
                     EnableTracingResponse(
                         exitCode = RESULT_CODE_ERROR_BINARY_VERIFICATION_ERROR,
-                        errorMessage = t.toErrorMessage()
+                        errorMessage = errorMessage(t)
                     )
                 is UnsatisfiedLinkError ->
                     EnableTracingResponse(
                         exitCode = RESULT_CODE_ERROR_BINARY_MISSING,
-                        errorMessage = t.toErrorMessage()
+                        errorMessage = errorMessage(t)
                     )
                 is Exception ->
                     EnableTracingResponse(
                         exitCode = RESULT_CODE_ERROR_OTHER,
-                        errorMessage = t.toErrorMessage()
+                        errorMessage = errorMessage(t)
                     )
                 else -> throw t
             }
@@ -128,7 +127,7 @@
         try {
             PerfettoNative.nativeRegisterWithPerfetto()
         } catch (e: Exception) {
-            return EnableTracingResponse(RESULT_CODE_ERROR_OTHER, errorMessage = e.toErrorMessage())
+            return EnableTracingResponse(RESULT_CODE_ERROR_OTHER, errorMessage = errorMessage(e))
         }
 
         isEnabled = true
@@ -136,27 +135,29 @@
     }
 
     // TODO: remove and replace with an observer wired into Perfetto
-    fun flushEvents() {
+    internal fun flushEvents() {
         if (isEnabled) {
             PerfettoNative.nativeFlushEvents()
         }
     }
 
+    /** Writes a trace message to indicate that a given section of code has begun. */
     fun traceEventStart(key: Int, traceInfo: String) {
         if (isEnabled) {
             PerfettoNative.nativeTraceEventBegin(key, traceInfo)
         }
     }
 
+    /** Writes a trace message to indicate that a given section of code has ended. */
     fun traceEventEnd() {
         if (isEnabled) PerfettoNative.nativeTraceEventEnd()
     }
 
-    data class EnableTracingResponse(
+    internal data class EnableTracingResponse(
         @EnableTracingResultCode val exitCode: Int,
         val errorMessage: String? = null
     ) {
-        fun toJsonString(): String {
+        internal fun toJsonString(): String {
             val output = StringWriter()
 
             JsonWriter(output).use {
@@ -179,7 +180,7 @@
             return output.toString()
         }
     }
-}
 
-internal fun Throwable.toErrorMessage(): String =
-    javaClass.name + if (message != null) ": $message" else ""
+    internal fun errorMessage(t: Throwable): String =
+        t.javaClass.name + if (t.message != null) ": ${t.message}" else ""
+}
diff --git a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt
index a7d4ab1..1c0f0db9 100644
--- a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt
+++ b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt
@@ -24,6 +24,7 @@
 import androidx.annotation.RestrictTo
 import androidx.annotation.RestrictTo.Scope.LIBRARY
 import androidx.tracing.perfetto.Tracing.EnableTracingResponse
+import androidx.tracing.perfetto.Tracing.errorMessage
 import androidx.tracing.perfetto.TracingReceiver.Companion.ACTION_ENABLE_TRACING
 import java.io.File
 import java.util.concurrent.LinkedBlockingQueue
@@ -127,7 +128,7 @@
                 } catch (e: Exception) {
                     EnableTracingResponse(
                         exitCode = RESULT_CODE_ERROR_OTHER,
-                        errorMessage = e.toErrorMessage()
+                        errorMessage = errorMessage(e)
                     )
                 }
             }
diff --git a/transition/transition/lint-baseline.xml b/transition/transition/lint-baseline.xml
index 72dfc05..97a7ae8 100644
--- a/transition/transition/lint-baseline.xml
+++ b/transition/transition/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="ResourceType"
@@ -217,1417 +217,4 @@
             file="src/main/java/androidx/transition/Styleable.java"/>
     </issue>
 
-    <issue
-        id="BanUncheckedReflection"
-        message="Calling `Method.invoke` without an SDK check"
-        errorLine1="                        (View) sAddGhostMethod.invoke(null, view, viewGroup, matrix));"
-        errorLine2="                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/GhostViewPlatform.java"/>
-    </issue>
-
-    <issue
-        id="BanUncheckedReflection"
-        message="Calling `Method.invoke` without an SDK check"
-        errorLine1="                sRemoveGhostMethod.invoke(null, view);"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/GhostViewPlatform.java"/>
-    </issue>
-
-    <issue
-        id="BanUncheckedReflection"
-        message="Calling `Method.invoke` without an SDK check"
-        errorLine1="                sCancelMethod.invoke(t);"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewGroupUtilsApi14.java"/>
-    </issue>
-
-    <issue
-        id="BanUncheckedReflection"
-        message="Calling `Method.invoke` without an SDK check"
-        errorLine1="                    sInvalidateChildInParentFastMethod.invoke(mHostView, left, top, dirty);"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewOverlayApi14.java"/>
-    </issue>
-
-    <issue
-        id="BanUncheckedReflection"
-        message="Calling `Method.invoke` without an SDK check"
-        errorLine1="                sSetFrameMethod.invoke(v, left, top, right, bottom);"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewUtilsBase.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 19; however, the containing class androidx.transition.AnimatorUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            animator.addPauseListener(listener);"
-        errorLine2="                     ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/AnimatorUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 19; however, the containing class androidx.transition.AnimatorUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            animator.pause();"
-        errorLine2="                     ~~~~~">
-        <location
-            file="src/main/java/androidx/transition/AnimatorUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 19; however, the containing class androidx.transition.AnimatorUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            animator.resume();"
-        errorLine2="                     ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/AnimatorUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.CanvasUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                canvas.enableZ();"
-        errorLine2="                       ~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/CanvasUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.CanvasUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                canvas.disableZ();"
-        errorLine2="                       ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/CanvasUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 21; however, the containing class androidx.transition.GhostViewHolder is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            if (view.getZ() != comparedWith.getZ()) {"
-        errorLine2="                     ~~~~">
-        <location
-            file="src/main/java/androidx/transition/GhostViewHolder.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 21; however, the containing class androidx.transition.GhostViewHolder is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            if (view.getZ() != comparedWith.getZ()) {"
-        errorLine2="                                            ~~~~">
-        <location
-            file="src/main/java/androidx/transition/GhostViewHolder.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 21; however, the containing class androidx.transition.GhostViewHolder is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                return view.getZ() > comparedWith.getZ();"
-        errorLine2="                            ~~~~">
-        <location
-            file="src/main/java/androidx/transition/GhostViewHolder.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 21; however, the containing class androidx.transition.GhostViewHolder is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                return view.getZ() > comparedWith.getZ();"
-        errorLine2="                                                  ~~~~">
-        <location
-            file="src/main/java/androidx/transition/GhostViewHolder.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ImageViewUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            view.animateTransform(matrix);"
-        errorLine2="                 ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ImageViewUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ImageViewUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                view.animateTransform(matrix);"
-        errorLine2="                     ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ImageViewUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 21; however, the containing class androidx.transition.ObjectAnimatorUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            return ObjectAnimator.ofObject(target, property, null, path);"
-        errorLine2="                                  ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ObjectAnimatorUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 21; however, the containing class androidx.transition.PropertyValuesHolderUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            return PropertyValuesHolder.ofObject(property, null, path);"
-        errorLine2="                                        ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/PropertyValuesHolderUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 19; however, the containing class androidx.transition.TransitionUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            addToOverlay = !view.isAttachedToWindow();"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 19; however, the containing class androidx.transition.TransitionUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            sceneRootIsAttached = sceneRoot == null ? false : sceneRoot.isAttachedToWindow();"
-        errorLine2="                                                                        ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 18; however, the containing class androidx.transition.TransitionUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            sceneRoot.getOverlay().add(view);"
-        errorLine2="                      ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 18; however, the containing class androidx.transition.TransitionUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            sceneRoot.getOverlay().add(view);"
-        errorLine2="                                   ~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 28; however, the containing class androidx.transition.TransitionUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                bitmap = Bitmap.createBitmap(picture);"
-        errorLine2="                                ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 18; however, the containing class androidx.transition.TransitionUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            sceneRoot.getOverlay().remove(view);"
-        errorLine2="                      ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 18; however, the containing class androidx.transition.TransitionUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            sceneRoot.getOverlay().remove(view);"
-        errorLine2="                                   ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ViewGroupUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            group.suppressLayout(suppress);"
-        errorLine2="                  ~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewGroupUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ViewGroupUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                group.suppressLayout(suppress);"
-        errorLine2="                      ~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewGroupUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ViewGroupUtils is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            return viewGroup.getChildDrawingOrder(i);"
-        errorLine2="                             ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewGroupUtils.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ViewUtilsApi19 is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                view.setTransitionAlpha(alpha);"
-        errorLine2="                     ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewUtilsApi19.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ViewUtilsApi19 is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                return view.getTransitionAlpha();"
-        errorLine2="                            ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewUtilsApi19.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ViewUtilsApi21 is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                view.transformMatrixToGlobal(matrix);"
-        errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewUtilsApi21.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ViewUtilsApi21 is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                view.transformMatrixToLocal(matrix);"
-        errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewUtilsApi21.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ViewUtilsApi21 is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                view.setAnimationMatrix(matrix);"
-        errorLine2="                     ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewUtilsApi21.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ViewUtilsApi22 is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                v.setLeftTopRightBottom(left, top, right, bottom);"
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewUtilsApi22.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 29; however, the containing class androidx.transition.ViewUtilsApi23 is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                    view.setTransitionVisibility(visibility);"
-        errorLine2="                         ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/ViewUtilsApi23.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public long getStartDelay(ViewGroup sceneRoot, Transition transition,"
-        errorLine2="                              ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/CircularPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public long getStartDelay(ViewGroup sceneRoot, Transition transition,"
-        errorLine2="                                                   ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/CircularPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/CircularPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="                                          ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/CircularPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onAppear(ViewGroup sceneRoot, View view,"
-        errorLine2="                             ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Explode.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onAppear(ViewGroup sceneRoot, View view,"
-        errorLine2="                                                  ~~~~">
-        <location
-            file="src/main/java/androidx/transition/Explode.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Explode.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="                                          ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Explode.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, View view,"
-        errorLine2="                                ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Explode.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, View view,"
-        errorLine2="                                                     ~~~~">
-        <location
-            file="src/main/java/androidx/transition/Explode.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Explode.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="                                          ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Explode.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onAppear(ViewGroup sceneRoot, View view,"
-        errorLine2="                             ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Fade.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onAppear(ViewGroup sceneRoot, View view,"
-        errorLine2="                                                  ~~~~">
-        <location
-            file="src/main/java/androidx/transition/Fade.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues,"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Fade.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues endValues) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Fade.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, final View view, TransitionValues startValues,"
-        errorLine2="                                ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Fade.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, final View view, TransitionValues startValues,"
-        errorLine2="                                                           ~~~~">
-        <location
-            file="src/main/java/androidx/transition/Fade.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, final View view, TransitionValues startValues,"
-        errorLine2="                                                                      ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Fade.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues endValues) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Fade.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public boolean canHandle(Object transition) {"
-        errorLine2="                             ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Object cloneTransition(Object transition) {"
-        errorLine2="           ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Object cloneTransition(Object transition) {"
-        errorLine2="                                  ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Object wrapTransitionInSet(Object transition) {"
-        errorLine2="           ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Object wrapTransitionInSet(Object transition) {"
-        errorLine2="                                      ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void setSharedElementTargets(Object transitionObj,"
-        errorLine2="                                        ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            View nonExistentView, ArrayList&lt;View> sharedViews) {"
-        errorLine2="            ~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            View nonExistentView, ArrayList&lt;View> sharedViews) {"
-        errorLine2="                                  ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void setEpicenter(Object transitionObj, View view) {"
-        errorLine2="                             ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void setEpicenter(Object transitionObj, View view) {"
-        errorLine2="                                                   ~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void addTargets(Object transitionObj, ArrayList&lt;View> views) {"
-        errorLine2="                           ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void addTargets(Object transitionObj, ArrayList&lt;View> views) {"
-        errorLine2="                                                 ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Object mergeTransitionsTogether(Object transition1, Object transition2,"
-        errorLine2="           ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Object mergeTransitionsTogether(Object transition1, Object transition2,"
-        errorLine2="                                           ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Object mergeTransitionsTogether(Object transition1, Object transition2,"
-        errorLine2="                                                               ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Object transition3) {"
-        errorLine2="            ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void scheduleHideFragmentView(Object exitTransitionObj, final View fragmentView,"
-        errorLine2="                                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void scheduleHideFragmentView(Object exitTransitionObj, final View fragmentView,"
-        errorLine2="                                                                         ~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            final ArrayList&lt;View> exitingViews) {"
-        errorLine2="                  ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Object mergeTransitionsInSequence(Object exitTransitionObj,"
-        errorLine2="           ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Object mergeTransitionsInSequence(Object exitTransitionObj,"
-        errorLine2="                                             ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Object enterTransitionObj, Object sharedElementTransitionObj) {"
-        errorLine2="            ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            Object enterTransitionObj, Object sharedElementTransitionObj) {"
-        errorLine2="                                       ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void beginDelayedTransition(ViewGroup sceneRoot, Object transition) {"
-        errorLine2="                                       ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void beginDelayedTransition(ViewGroup sceneRoot, Object transition) {"
-        errorLine2="                                                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void scheduleRemoveTargets(final Object overallTransitionObj,"
-        errorLine2="                                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            final Object enterTransition, final ArrayList&lt;View> enteringViews,"
-        errorLine2="                  ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            final Object enterTransition, final ArrayList&lt;View> enteringViews,"
-        errorLine2="                                                ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            final Object exitTransition, final ArrayList&lt;View> exitingViews,"
-        errorLine2="                  ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            final Object exitTransition, final ArrayList&lt;View> exitingViews,"
-        errorLine2="                                               ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            final Object sharedElementTransition, final ArrayList&lt;View> sharedElementsIn) {"
-        errorLine2="                  ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            final Object sharedElementTransition, final ArrayList&lt;View> sharedElementsIn) {"
-        errorLine2="                                                        ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void swapSharedElementTargets(Object sharedElementTransitionObj,"
-        errorLine2="                                         ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ArrayList&lt;View> sharedElementsOut, ArrayList&lt;View> sharedElementsIn) {"
-        errorLine2="            ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ArrayList&lt;View> sharedElementsOut, ArrayList&lt;View> sharedElementsIn) {"
-        errorLine2="                                               ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void replaceTargets(Object transitionObj, ArrayList&lt;View> oldTargets,"
-        errorLine2="                               ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void replaceTargets(Object transitionObj, ArrayList&lt;View> oldTargets,"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            ArrayList&lt;View> newTargets) {"
-        errorLine2="            ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void addTarget(Object transitionObj, View view) {"
-        errorLine2="                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void addTarget(Object transitionObj, View view) {"
-        errorLine2="                                                ~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void removeTarget(Object transitionObj, View view) {"
-        errorLine2="                             ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void removeTarget(Object transitionObj, View view) {"
-        errorLine2="                                                   ~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void setEpicenter(Object transitionObj, final Rect epicenter) {"
-        errorLine2="                             ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void setEpicenter(Object transitionObj, final Rect epicenter) {"
-        errorLine2="                                                         ~~~~">
-        <location
-            file="src/main/java/androidx/transition/FragmentTransitionSupport.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public PatternPathMotion(Path patternPath) {"
-        errorLine2="                             ~~~~">
-        <location
-            file="src/main/java/androidx/transition/PatternPathMotion.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Path getPatternPath() {"
-        errorLine2="           ~~~~">
-        <location
-            file="src/main/java/androidx/transition/PatternPathMotion.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void setPatternPath(Path patternPath) {"
-        errorLine2="                               ~~~~">
-        <location
-            file="src/main/java/androidx/transition/PatternPathMotion.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public long getStartDelay(ViewGroup sceneRoot, Transition transition,"
-        errorLine2="                              ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/SidePropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public long getStartDelay(ViewGroup sceneRoot, Transition transition,"
-        errorLine2="                                                   ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/SidePropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/SidePropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="                                          ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/SidePropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onAppear(ViewGroup sceneRoot, View view,"
-        errorLine2="                             ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Slide.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onAppear(ViewGroup sceneRoot, View view,"
-        errorLine2="                                                  ~~~~">
-        <location
-            file="src/main/java/androidx/transition/Slide.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Slide.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="                                          ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Slide.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, View view,"
-        errorLine2="                                ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Slide.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, View view,"
-        errorLine2="                                                     ~~~~">
-        <location
-            file="src/main/java/androidx/transition/Slide.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Slide.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues) {"
-        errorLine2="                                          ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Slide.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void setMatchOrder(@MatchOrder int... matches) {"
-        errorLine2="                                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Transition.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void pause(View sceneRoot) {"
-        errorLine2="                      ~~~~">
-        <location
-            file="src/main/java/androidx/transition/Transition.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void resume(View sceneRoot) {"
-        errorLine2="                       ~~~~">
-        <location
-            file="src/main/java/androidx/transition/Transition.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected void animate(Animator animator) {"
-        errorLine2="                           ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Transition.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Transition clone() {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Transition.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="        public abstract Rect onGetEpicenter(@NonNull Transition transition);"
-        errorLine2="                        ~~~~">
-        <location
-            file="src/main/java/androidx/transition/Transition.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Transition inflateTransition(int resource) {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionInflater.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public TransitionManager inflateTransitionManager(int resource, ViewGroup sceneRoot) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionInflater.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public TransitionManager inflateTransitionManager(int resource, ViewGroup sceneRoot) {"
-        errorLine2="                                                                    ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionInflater.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public static void endTransitions(final ViewGroup sceneRoot) {"
-        errorLine2="                                            ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionManager.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public abstract long getStartDelay(ViewGroup sceneRoot, Transition transition,"
-        errorLine2="                                       ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public abstract long getStartDelay(ViewGroup sceneRoot, Transition transition,"
-        errorLine2="                                                            ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues);"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues startValues, TransitionValues endValues);"
-        errorLine2="                                          ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public abstract void captureValues(TransitionValues transitionValues);"
-        errorLine2="                                       ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public abstract String[] getPropagationProperties();"
-        errorLine2="                    ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void setPathMotion(PathMotion pathMotion) {"
-        errorLine2="                              ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionSet.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void pause(View sceneRoot) {"
-        errorLine2="                      ~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionSet.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void resume(View sceneRoot) {"
-        errorLine2="                       ~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionSet.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void setPropagation(TransitionPropagation transitionPropagation) {"
-        errorLine2="                               ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionSet.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void setEpicenterCallback(EpicenterCallback epicenterCallback) {"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionSet.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Transition clone() {"
-        errorLine2="           ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionSet.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public View view;"
-        errorLine2="           ~~~~">
-        <location
-            file="src/main/java/androidx/transition/TransitionValues.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public boolean isVisible(TransitionValues values) {"
-        errorLine2="                             ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,"
-        errorLine2="                             ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onAppear(ViewGroup sceneRoot, TransitionValues startValues, int startVisibility,"
-        errorLine2="                                                  ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues endValues, int endVisibility) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,"
-        errorLine2="                             ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,"
-        errorLine2="                                                  ~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,"
-        errorLine2="                                                             ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues endValues) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,"
-        errorLine2="                                ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, TransitionValues startValues,"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            int startVisibility, TransitionValues endValues, int endVisibility) {"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,"
-        errorLine2="                                ~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,"
-        errorLine2="                                                     ~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,"
-        errorLine2="                                                                ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="            TransitionValues endValues) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/Visibility.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void captureValues(TransitionValues transitionValues) {"
-        errorLine2="                              ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/VisibilityPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public String[] getPropagationProperties() {"
-        errorLine2="           ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/VisibilityPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public int getViewVisibility(TransitionValues values) {"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/VisibilityPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public int getViewX(TransitionValues values) {"
-        errorLine2="                        ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/VisibilityPropagation.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public int getViewY(TransitionValues values) {"
-        errorLine2="                        ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/transition/VisibilityPropagation.java"/>
-    </issue>
-
 </issues>
diff --git a/tvprovider/tvprovider/lint-baseline.xml b/tvprovider/tvprovider/lint-baseline.xml
index 739a5b3..5f3b54c 100644
--- a/tvprovider/tvprovider/lint-baseline.xml
+++ b/tvprovider/tvprovider/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="ClassVerificationFailure"
diff --git a/vectordrawable/integration-tests/testapp/src/main/java/com/example/android/support/vectordrawable/app/AVDCListenerDemo.java b/vectordrawable/integration-tests/testapp/src/main/java/com/example/android/support/vectordrawable/app/AVDCListenerDemo.java
index 37a162b..1b6cba4 100644
--- a/vectordrawable/integration-tests/testapp/src/main/java/com/example/android/support/vectordrawable/app/AVDCListenerDemo.java
+++ b/vectordrawable/integration-tests/testapp/src/main/java/com/example/android/support/vectordrawable/app/AVDCListenerDemo.java
@@ -23,6 +23,7 @@
 import android.view.View;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.widget.AppCompatImageView;
 import androidx.vectordrawable.graphics.drawable.Animatable2Compat;
@@ -57,24 +58,24 @@
         Animatable2Compat.AnimationCallback textView1Callback = new
                 Animatable2Compat.AnimationCallback() {
                     @Override
-                    public void onAnimationStart(Drawable drawable) {
+                    public void onAnimationStart(@NonNull Drawable drawable) {
                         textView1.setText("AVD 1 started");
                     }
 
                     @Override
-                    public void onAnimationEnd(Drawable drawable) {
+                    public void onAnimationEnd(@NonNull Drawable drawable) {
                         textView1.setText("AVD 1 Ended");
                     }
                 };
         Animatable2Compat.AnimationCallback textView2Callback = new
                 Animatable2Compat.AnimationCallback() {
                     @Override
-                    public void onAnimationStart(Drawable drawable) {
+                    public void onAnimationStart(@NonNull Drawable drawable) {
                         textView2.setText("AVD 1 started");
                     }
 
                     @Override
-                    public void onAnimationEnd(Drawable drawable) {
+                    public void onAnimationEnd(@NonNull Drawable drawable) {
                         textView2.setText("AVD 1 Ended");
                     }
                 };
@@ -86,12 +87,12 @@
         AnimatedVectorDrawableCompat.registerAnimationCallback(drawable2,
                 new Animatable2Compat.AnimationCallback() {
                     @Override
-                    public void onAnimationStart(Drawable drawable) {
+                    public void onAnimationStart(@NonNull Drawable drawable) {
                         textView3.setText("AVD 2 started");
                     }
 
                     @Override
-                    public void onAnimationEnd(Drawable drawable) {
+                    public void onAnimationEnd(@NonNull Drawable drawable) {
                         textView3.setText("AVD 2 Ended");
                     }
                 });
@@ -99,12 +100,12 @@
         Animatable2Compat.AnimationCallback textView4Callback = new
                 Animatable2Compat.AnimationCallback() {
                     @Override
-                    public void onAnimationStart(Drawable drawable) {
+                    public void onAnimationStart(@NonNull Drawable drawable) {
                         textView4.setText("AVD 2 started");
                     }
 
                     @Override
-                    public void onAnimationEnd(Drawable drawable) {
+                    public void onAnimationEnd(@NonNull Drawable drawable) {
                         textView4.setText("AVD 2 Ended");
                     }
                 };
diff --git a/vectordrawable/vectordrawable-animated/api/1.2.0-beta01.txt b/vectordrawable/vectordrawable-animated/api/1.2.0-beta01.txt
index 4c7b6cc..683796b 100644
--- a/vectordrawable/vectordrawable-animated/api/1.2.0-beta01.txt
+++ b/vectordrawable/vectordrawable-animated/api/1.2.0-beta01.txt
@@ -9,27 +9,27 @@
 
   public abstract static class Animatable2Compat.AnimationCallback {
     ctor public Animatable2Compat.AnimationCallback();
-    method public void onAnimationEnd(android.graphics.drawable.Drawable!);
-    method public void onAnimationStart(android.graphics.drawable.Drawable!);
+    method public void onAnimationEnd(android.graphics.drawable.Drawable);
+    method public void onAnimationStart(android.graphics.drawable.Drawable);
   }
 
   public class AnimatedVectorDrawableCompat extends android.graphics.drawable.Drawable implements androidx.vectordrawable.graphics.drawable.Animatable2Compat {
     method public void clearAnimationCallbacks();
-    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable!);
+    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable?);
     method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat? create(android.content.Context, @DrawableRes int);
-    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat! createFromXmlInner(android.content.Context!, android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat createFromXmlInner(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public boolean isRunning();
-    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static void registerAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static void registerAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
     method public void start();
     method public void stop();
-    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
   }
 
 }
diff --git a/vectordrawable/vectordrawable-animated/api/current.txt b/vectordrawable/vectordrawable-animated/api/current.txt
index 4c7b6cc..683796b 100644
--- a/vectordrawable/vectordrawable-animated/api/current.txt
+++ b/vectordrawable/vectordrawable-animated/api/current.txt
@@ -9,27 +9,27 @@
 
   public abstract static class Animatable2Compat.AnimationCallback {
     ctor public Animatable2Compat.AnimationCallback();
-    method public void onAnimationEnd(android.graphics.drawable.Drawable!);
-    method public void onAnimationStart(android.graphics.drawable.Drawable!);
+    method public void onAnimationEnd(android.graphics.drawable.Drawable);
+    method public void onAnimationStart(android.graphics.drawable.Drawable);
   }
 
   public class AnimatedVectorDrawableCompat extends android.graphics.drawable.Drawable implements androidx.vectordrawable.graphics.drawable.Animatable2Compat {
     method public void clearAnimationCallbacks();
-    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable!);
+    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable?);
     method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat? create(android.content.Context, @DrawableRes int);
-    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat! createFromXmlInner(android.content.Context!, android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat createFromXmlInner(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public boolean isRunning();
-    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static void registerAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static void registerAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
     method public void start();
     method public void stop();
-    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
   }
 
 }
diff --git a/vectordrawable/vectordrawable-animated/api/public_plus_experimental_1.2.0-beta01.txt b/vectordrawable/vectordrawable-animated/api/public_plus_experimental_1.2.0-beta01.txt
index 4c7b6cc..683796b 100644
--- a/vectordrawable/vectordrawable-animated/api/public_plus_experimental_1.2.0-beta01.txt
+++ b/vectordrawable/vectordrawable-animated/api/public_plus_experimental_1.2.0-beta01.txt
@@ -9,27 +9,27 @@
 
   public abstract static class Animatable2Compat.AnimationCallback {
     ctor public Animatable2Compat.AnimationCallback();
-    method public void onAnimationEnd(android.graphics.drawable.Drawable!);
-    method public void onAnimationStart(android.graphics.drawable.Drawable!);
+    method public void onAnimationEnd(android.graphics.drawable.Drawable);
+    method public void onAnimationStart(android.graphics.drawable.Drawable);
   }
 
   public class AnimatedVectorDrawableCompat extends android.graphics.drawable.Drawable implements androidx.vectordrawable.graphics.drawable.Animatable2Compat {
     method public void clearAnimationCallbacks();
-    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable!);
+    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable?);
     method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat? create(android.content.Context, @DrawableRes int);
-    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat! createFromXmlInner(android.content.Context!, android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat createFromXmlInner(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public boolean isRunning();
-    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static void registerAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static void registerAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
     method public void start();
     method public void stop();
-    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
   }
 
 }
diff --git a/vectordrawable/vectordrawable-animated/api/public_plus_experimental_current.txt b/vectordrawable/vectordrawable-animated/api/public_plus_experimental_current.txt
index 4c7b6cc..683796b 100644
--- a/vectordrawable/vectordrawable-animated/api/public_plus_experimental_current.txt
+++ b/vectordrawable/vectordrawable-animated/api/public_plus_experimental_current.txt
@@ -9,27 +9,27 @@
 
   public abstract static class Animatable2Compat.AnimationCallback {
     ctor public Animatable2Compat.AnimationCallback();
-    method public void onAnimationEnd(android.graphics.drawable.Drawable!);
-    method public void onAnimationStart(android.graphics.drawable.Drawable!);
+    method public void onAnimationEnd(android.graphics.drawable.Drawable);
+    method public void onAnimationStart(android.graphics.drawable.Drawable);
   }
 
   public class AnimatedVectorDrawableCompat extends android.graphics.drawable.Drawable implements androidx.vectordrawable.graphics.drawable.Animatable2Compat {
     method public void clearAnimationCallbacks();
-    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable!);
+    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable?);
     method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat? create(android.content.Context, @DrawableRes int);
-    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat! createFromXmlInner(android.content.Context!, android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat createFromXmlInner(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public boolean isRunning();
-    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static void registerAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static void registerAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
     method public void start();
     method public void stop();
-    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
   }
 
 }
diff --git a/vectordrawable/vectordrawable-animated/api/restricted_1.2.0-beta01.txt b/vectordrawable/vectordrawable-animated/api/restricted_1.2.0-beta01.txt
index c094267..5221d91 100644
--- a/vectordrawable/vectordrawable-animated/api/restricted_1.2.0-beta01.txt
+++ b/vectordrawable/vectordrawable-animated/api/restricted_1.2.0-beta01.txt
@@ -9,31 +9,31 @@
 
   public abstract static class Animatable2Compat.AnimationCallback {
     ctor public Animatable2Compat.AnimationCallback();
-    method public void onAnimationEnd(android.graphics.drawable.Drawable!);
-    method public void onAnimationStart(android.graphics.drawable.Drawable!);
+    method public void onAnimationEnd(android.graphics.drawable.Drawable);
+    method public void onAnimationStart(android.graphics.drawable.Drawable);
   }
 
   public class AnimatedVectorDrawableCompat extends android.graphics.drawable.Drawable implements androidx.vectordrawable.graphics.drawable.Animatable2Compat androidx.core.graphics.drawable.TintAwareDrawable {
     method public void clearAnimationCallbacks();
-    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable!);
+    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable?);
     method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat? create(android.content.Context, @DrawableRes int);
-    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat! createFromXmlInner(android.content.Context!, android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat createFromXmlInner(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public boolean isRunning();
-    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static void registerAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static void registerAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
     method public void start();
     method public void stop();
-    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class AnimationUtilsCompat {
-    method public static android.view.animation.Interpolator! loadInterpolator(android.content.Context!, int) throws android.content.res.Resources.NotFoundException;
+    method public static android.view.animation.Interpolator loadInterpolator(android.content.Context, @AnimRes int) throws android.content.res.Resources.NotFoundException;
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class AnimatorInflaterCompat {
@@ -42,10 +42,10 @@
     method public static android.animation.Animator! loadAnimator(android.content.Context!, android.content.res.Resources!, android.content.res.Resources.Theme!, @AnimatorRes int, float) throws android.content.res.Resources.NotFoundException;
   }
 
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ArgbEvaluator implements android.animation.TypeEvaluator {
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ArgbEvaluator implements android.animation.TypeEvaluator<java.lang.Object> {
     ctor public ArgbEvaluator();
     method public Object! evaluate(float, Object!, Object!);
-    method public static androidx.vectordrawable.graphics.drawable.ArgbEvaluator! getInstance();
+    method public static androidx.vectordrawable.graphics.drawable.ArgbEvaluator getInstance();
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class PathInterpolatorCompat implements android.view.animation.Interpolator {
diff --git a/vectordrawable/vectordrawable-animated/api/restricted_current.txt b/vectordrawable/vectordrawable-animated/api/restricted_current.txt
index c094267..5221d91 100644
--- a/vectordrawable/vectordrawable-animated/api/restricted_current.txt
+++ b/vectordrawable/vectordrawable-animated/api/restricted_current.txt
@@ -9,31 +9,31 @@
 
   public abstract static class Animatable2Compat.AnimationCallback {
     ctor public Animatable2Compat.AnimationCallback();
-    method public void onAnimationEnd(android.graphics.drawable.Drawable!);
-    method public void onAnimationStart(android.graphics.drawable.Drawable!);
+    method public void onAnimationEnd(android.graphics.drawable.Drawable);
+    method public void onAnimationStart(android.graphics.drawable.Drawable);
   }
 
   public class AnimatedVectorDrawableCompat extends android.graphics.drawable.Drawable implements androidx.vectordrawable.graphics.drawable.Animatable2Compat androidx.core.graphics.drawable.TintAwareDrawable {
     method public void clearAnimationCallbacks();
-    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable!);
+    method public static void clearAnimationCallbacks(android.graphics.drawable.Drawable?);
     method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat? create(android.content.Context, @DrawableRes int);
-    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat! createFromXmlInner(android.content.Context!, android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat createFromXmlInner(android.content.Context, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public boolean isRunning();
-    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static void registerAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public void registerAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static void registerAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
     method public void start();
     method public void stop();
-    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback);
-    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable!, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback!);
+    method public boolean unregisterAnimationCallback(androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
+    method public static boolean unregisterAnimationCallback(android.graphics.drawable.Drawable?, androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback?);
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class AnimationUtilsCompat {
-    method public static android.view.animation.Interpolator! loadInterpolator(android.content.Context!, int) throws android.content.res.Resources.NotFoundException;
+    method public static android.view.animation.Interpolator loadInterpolator(android.content.Context, @AnimRes int) throws android.content.res.Resources.NotFoundException;
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class AnimatorInflaterCompat {
@@ -42,10 +42,10 @@
     method public static android.animation.Animator! loadAnimator(android.content.Context!, android.content.res.Resources!, android.content.res.Resources.Theme!, @AnimatorRes int, float) throws android.content.res.Resources.NotFoundException;
   }
 
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ArgbEvaluator implements android.animation.TypeEvaluator {
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ArgbEvaluator implements android.animation.TypeEvaluator<java.lang.Object> {
     ctor public ArgbEvaluator();
     method public Object! evaluate(float, Object!, Object!);
-    method public static androidx.vectordrawable.graphics.drawable.ArgbEvaluator! getInstance();
+    method public static androidx.vectordrawable.graphics.drawable.ArgbEvaluator getInstance();
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class PathInterpolatorCompat implements android.view.animation.Interpolator {
diff --git a/vectordrawable/vectordrawable-animated/build.gradle b/vectordrawable/vectordrawable-animated/build.gradle
index 8b3b6b3..75c6c2a 100644
--- a/vectordrawable/vectordrawable-animated/build.gradle
+++ b/vectordrawable/vectordrawable-animated/build.gradle
@@ -6,7 +6,9 @@
 }
 
 dependencies {
+    api("androidx.annotation:annotation:1.2.0")
     api(project(":vectordrawable:vectordrawable"))
+    implementation("androidx.core:core:1.6.0")
     implementation("androidx.interpolator:interpolator:1.0.0")
     implementation("androidx.collection:collection:1.1.0")
 
diff --git a/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/AnimatedVectorDrawableParameterizedTest.java b/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/AnimatedVectorDrawableParameterizedTest.java
index dcf1e26..5015314 100644
--- a/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/AnimatedVectorDrawableParameterizedTest.java
+++ b/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/AnimatedVectorDrawableParameterizedTest.java
@@ -26,6 +26,7 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 
+import androidx.annotation.NonNull;
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
@@ -101,12 +102,12 @@
 
         avd.registerAnimationCallback(new AnimationCallback() {
             @Override
-            public void onAnimationStart(Drawable drawable) {
+            public void onAnimationStart(@NonNull Drawable drawable) {
                 // Nothing to do.
             }
 
             @Override
-            public void onAnimationEnd(Drawable drawable) {
+            public void onAnimationEnd(@NonNull Drawable drawable) {
                 bitmap.eraseColor(0);
                 drawable.draw(c);
                 int centerColor = bitmap.getPixel(IMAGE_WIDTH / 2 , IMAGE_WIDTH / 2);
diff --git a/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/AnimatedVectorDrawableTest.java b/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/AnimatedVectorDrawableTest.java
index b2fa23a..7aae59ba7 100644
--- a/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/AnimatedVectorDrawableTest.java
+++ b/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/AnimatedVectorDrawableTest.java
@@ -39,6 +39,7 @@
 import android.widget.ImageButton;
 
 import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
 import androidx.core.view.ViewCompat;
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -93,13 +94,13 @@
             new AnimationCallback() {
                 @Override
                 public void onAnimationStart(
-                        Drawable drawable) {
+                        @NonNull Drawable drawable) {
                     mAnimationStarted = true;
                 }
 
                 @Override
                 public void onAnimationEnd(
-                        Drawable drawable) {
+                        @NonNull Drawable drawable) {
                     mAnimationEnded = true;
                 }
             };
@@ -486,12 +487,12 @@
 
         avd.registerAnimationCallback(new AnimationCallback() {
             @Override
-            public void onAnimationStart(Drawable drawable) {
+            public void onAnimationStart(@NonNull Drawable drawable) {
                 // Nothing to do.
             }
 
             @Override
-            public void onAnimationEnd(Drawable drawable) {
+            public void onAnimationEnd(@NonNull Drawable drawable) {
                 bitmap.eraseColor(0);
                 drawable.draw(c);
                 int centerColor = bitmap.getPixel(IMAGE_WIDTH / 2 , IMAGE_WIDTH / 2);
diff --git a/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/PathInterpolatorParameterizedTest.java b/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/PathInterpolatorParameterizedTest.java
index d643923..c33a254 100644
--- a/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/PathInterpolatorParameterizedTest.java
+++ b/vectordrawable/vectordrawable-animated/src/androidTest/java/androidx/vectordrawable/graphics/drawable/tests/PathInterpolatorParameterizedTest.java
@@ -23,6 +23,7 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 
+import androidx.annotation.NonNull;
 import androidx.test.filters.MediumTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
@@ -91,12 +92,12 @@
 
         avd.registerAnimationCallback(new Animatable2Compat.AnimationCallback() {
             @Override
-            public void onAnimationStart(Drawable drawable) {
+            public void onAnimationStart(@NonNull Drawable drawable) {
                 // Nothing to do.
             }
 
             @Override
-            public void onAnimationEnd(Drawable drawable) {
+            public void onAnimationEnd(@NonNull Drawable drawable) {
                 bitmap.eraseColor(0);
                 drawable.draw(c);
                 int centerColor = bitmap.getPixel(IMAGE_WIDTH / 2 , IMAGE_WIDTH / 2);
diff --git a/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/Animatable2Compat.java b/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/Animatable2Compat.java
index 7c61989..f5f900c 100644
--- a/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/Animatable2Compat.java
+++ b/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/Animatable2Compat.java
@@ -60,13 +60,13 @@
          *
          * @param drawable The drawable started the animation.
          */
-        public void onAnimationStart(Drawable drawable) {};
+        public void onAnimationStart(@NonNull Drawable drawable) {}
         /**
          * Called when the animation ends.
          *
          * @param drawable The drawable finished the animation.
          */
-        public void onAnimationEnd(Drawable drawable) {};
+        public void onAnimationEnd(@NonNull Drawable drawable) {}
 
         // Only when passing this Animatable2Compat.AnimationCallback to a frameworks' AVD, we need
         // to bridge this compat version callback with the frameworks' callback.
diff --git a/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/AnimatedVectorDrawableCompat.java b/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/AnimatedVectorDrawableCompat.java
index 78c2111..7c743a9 100644
--- a/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -21,6 +21,7 @@
 import android.animation.AnimatorSet;
 import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -31,6 +32,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Animatable2;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
@@ -38,6 +40,7 @@
 import android.util.Log;
 import android.util.Xml;
 
+import androidx.annotation.DoNotInline;
 import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -46,6 +49,7 @@
 import androidx.core.content.res.ResourcesCompat;
 import androidx.core.content.res.TypedArrayUtils;
 import androidx.core.graphics.drawable.DrawableCompat;
+import androidx.core.util.ObjectsCompat;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -57,8 +61,8 @@
 /**
  * For API 24 and above, this class is delegating to the framework's {@link
  * AnimatedVectorDrawable}.
- * For older API version, this class uses {@link android.animation.ObjectAnimator} and
- * {@link android.animation.AnimatorSet} to animate the properties of a
+ * For older API version, this class uses {@link ObjectAnimator} and
+ * {@link AnimatorSet} to animate the properties of a
  * {@link VectorDrawableCompat} to create an animated drawable.
  * <p/>
  * AnimatedVectorDrawableCompat are defined in the same XML format as
@@ -151,9 +155,10 @@
 
     private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
 
-    private AnimatedVectorDrawableCompatState mAnimatedVectorState;
+    @NonNull
+    private final AnimatedVectorDrawableCompatState mAnimatedVectorState;
 
-    private Context mContext;
+    private final Context mContext;
 
     private ArgbEvaluator mArgbEvaluator = null;
 
@@ -163,7 +168,7 @@
     private Animator.AnimatorListener mAnimatorListener = null;
 
     // Use an array to keep track of multiple call back associated with one drawable.
-    ArrayList<Animatable2Compat.AnimationCallback> mAnimationCallbacks = null;
+    ArrayList<AnimationCallback> mAnimationCallbacks = null;
 
 
     AnimatedVectorDrawableCompat() {
@@ -181,7 +186,7 @@
         if (state != null) {
             mAnimatedVectorState = state;
         } else {
-            mAnimatedVectorState = new AnimatedVectorDrawableCompatState(context, state, mCallback,
+            mAnimatedVectorState = new AnimatedVectorDrawableCompatState(context, null, mCallback,
                     res);
         }
     }
@@ -190,6 +195,7 @@
      * mutate() will be effective only if the getConstantState() is returning non-null.
      * Otherwise, it just return the current object without modification.
      */
+    @NonNull
     @Override
     public Drawable mutate() {
         if (mDelegateDrawable != null) {
@@ -213,11 +219,14 @@
             @DrawableRes int resId) {
         if (Build.VERSION.SDK_INT >= 24) {
             final AnimatedVectorDrawableCompat drawable = new AnimatedVectorDrawableCompat(context);
-            drawable.mDelegateDrawable = ResourcesCompat.getDrawable(context.getResources(), resId,
+            final Drawable delegate = ResourcesCompat.getDrawable(context.getResources(), resId,
                     context.getTheme());
-            drawable.mDelegateDrawable.setCallback(drawable.mCallback);
+            ObjectsCompat.requireNonNull(drawable, "Failed to load drawable");
+            //noinspection ConstantConditions
+            delegate.setCallback(drawable.mCallback);
             drawable.mCachedConstantStateDelegate = new AnimatedVectorDrawableDelegateState(
-                    drawable.mDelegateDrawable.getConstantState());
+                    delegate.getConstantState());
+            drawable.mDelegateDrawable = delegate;
             return drawable;
         }
         Resources resources = context.getResources();
@@ -226,6 +235,7 @@
             final XmlPullParser parser = resources.getXml(resId);
             final AttributeSet attrs = Xml.asAttributeSet(parser);
             int type;
+            //noinspection StatementWithEmptyBody
             while ((type = parser.next()) != XmlPullParser.START_TAG
                     && type != XmlPullParser.END_DOCUMENT) {
                 // Empty loop
@@ -249,9 +259,10 @@
      * document, tries to create a Drawable from that tag. Returns {@code null}
      * if the tag is not a valid drawable.
      */
-    public static AnimatedVectorDrawableCompat createFromXmlInner(Context context, Resources r,
-            XmlPullParser parser, AttributeSet attrs, Theme theme)
-            throws XmlPullParserException, IOException {
+    @NonNull
+    public static AnimatedVectorDrawableCompat createFromXmlInner(@NonNull Context context,
+            @NonNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs,
+            @Nullable Theme theme) throws XmlPullParserException, IOException {
         final AnimatedVectorDrawableCompat drawable = new AnimatedVectorDrawableCompat(context);
         drawable.inflate(r, parser, attrs, theme);
         return drawable;
@@ -262,6 +273,7 @@
      * <strong>Note</strong> that we don't support constant state when SDK < 24.
      * Make sure you check the return value before using it.
      */
+    @Nullable
     @Override
     public ConstantState getConstantState() {
         if (mDelegateDrawable != null && Build.VERSION.SDK_INT >= 24) {
@@ -282,7 +294,7 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
+    public void draw(@NonNull Canvas canvas) {
         if (mDelegateDrawable != null) {
             mDelegateDrawable.draw(canvas);
             return;
@@ -336,7 +348,7 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter colorFilter) {
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
         if (mDelegateDrawable != null) {
             mDelegateDrawable.setColorFilter(colorFilter);
             return;
@@ -344,6 +356,7 @@
         mAnimatedVectorState.mVectorDrawable.setColorFilter(colorFilter);
     }
 
+    @Nullable
     @Override
     public ColorFilter getColorFilter() {
         if (mDelegateDrawable != null) {
@@ -363,7 +376,7 @@
     }
 
     @Override
-    public void setTintList(ColorStateList tint) {
+    public void setTintList(@Nullable ColorStateList tint) {
         if (mDelegateDrawable != null) {
             DrawableCompat.setTintList(mDelegateDrawable, tint);
             return;
@@ -373,7 +386,7 @@
     }
 
     @Override
-    public void setTintMode(PorterDuff.Mode tintMode) {
+    public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
         if (mDelegateDrawable != null) {
             DrawableCompat.setTintMode(mDelegateDrawable, tintMode);
             return;
@@ -399,8 +412,6 @@
         return mAnimatedVectorState.mVectorDrawable.isStateful();
     }
 
-    // Remove deprecation suppression once b/120984759 is resolved
-    @SuppressWarnings("deprecation")
     @Override
     public int getOpacity() {
         if (mDelegateDrawable != null) {
@@ -443,7 +454,8 @@
     }
 
     @Override
-    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+    public void inflate(@NonNull Resources res, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         if (mDelegateDrawable != null) {
             DrawableCompat.inflate(mDelegateDrawable, res, parser, attrs, theme);
@@ -473,6 +485,7 @@
                     if (drawableRes != 0) {
                         VectorDrawableCompat vectorDrawable = VectorDrawableCompat.create(res,
                                 drawableRes, theme);
+                        ObjectsCompat.requireNonNull(vectorDrawable, "Failed to load drawable");
                         vectorDrawable.setAllowCaching(false);
                         vectorDrawable.setCallback(mCallback);
                         if (mAnimatedVectorState.mVectorDrawable != null) {
@@ -482,8 +495,7 @@
                     }
                     a.recycle();
                 } else if (TARGET.equals(tagName)) {
-                    final TypedArray a =
-                            res.obtainAttributes(attrs,
+                    final TypedArray a = res.obtainAttributes(attrs,
                                     AndroidResources.STYLEABLE_ANIMATED_VECTOR_DRAWABLE_TARGET);
                     final String target = a.getString(
                             AndroidResources.STYLEABLE_ANIMATED_VECTOR_DRAWABLE_TARGET_NAME);
@@ -514,19 +526,17 @@
     }
 
     @Override
-    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs)
-            throws XmlPullParserException, IOException {
+    public void inflate(@NonNull Resources res, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs) throws XmlPullParserException, IOException {
         inflate(res, parser, attrs, null);
     }
 
     @Override
-    public void applyTheme(Theme t) {
+    public void applyTheme(@NonNull Theme t) {
         if (mDelegateDrawable != null) {
             DrawableCompat.applyTheme(mDelegateDrawable, t);
-            return;
         }
         // TODO: support theming in older platform.
-        return;
     }
 
     @Override
@@ -597,6 +607,7 @@
         ArrayList<Animator> mAnimators;
         ArrayMap<Animator, String> mTargetNameMap;
 
+        @SuppressWarnings("unused")
         AnimatedVectorDrawableCompatState(Context context,
                 AnimatedVectorDrawableCompatState copy, Callback owner, Resources res) {
             if (copy != null) {
@@ -615,8 +626,8 @@
                 }
                 if (copy.mAnimators != null) {
                     final int numAnimators = copy.mAnimators.size();
-                    mAnimators = new ArrayList<Animator>(numAnimators);
-                    mTargetNameMap = new ArrayMap<Animator, String>(numAnimators);
+                    mAnimators = new ArrayList<>(numAnimators);
+                    mTargetNameMap = new ArrayMap<>(numAnimators);
                     for (int i = 0; i < numAnimators; ++i) {
                         Animator anim = copy.mAnimators.get(i);
                         Animator animClone = anim.clone();
@@ -687,8 +698,8 @@
             setupColorAnimator(animator);
         }
         if (mAnimatedVectorState.mAnimators == null) {
-            mAnimatedVectorState.mAnimators = new ArrayList<Animator>();
-            mAnimatedVectorState.mTargetNameMap = new ArrayMap<Animator, String>();
+            mAnimatedVectorState.mAnimators = new ArrayList<>();
+            mAnimatedVectorState.mTargetNameMap = new ArrayMap<>();
         }
         mAnimatedVectorState.mAnimators.add(animator);
         mAnimatedVectorState.mTargetNameMap.put(animator, name);
@@ -697,19 +708,19 @@
         }
     }
 
+    @SuppressLint("NewApi") // mDelegateDrawable != null is an implicit API check
     @Override
     public boolean isRunning() {
         if (mDelegateDrawable != null) {
-            //noinspection AndroidLintNewApi - Implicit when delegate is non-null.
             return ((AnimatedVectorDrawable) mDelegateDrawable).isRunning();
         }
         return mAnimatedVectorState.mAnimatorSet.isRunning();
     }
 
+    @SuppressLint("NewApi") // mDelegateDrawable != null is an implicit API check
     @Override
     public void start() {
         if (mDelegateDrawable != null) {
-            //noinspection AndroidLintNewApi - Implicit when delegate is non-null.
             ((AnimatedVectorDrawable) mDelegateDrawable).start();
             return;
         }
@@ -722,10 +733,10 @@
         invalidateSelf();
     }
 
+    @SuppressLint("NewApi") // mDelegateDrawable != null is an implicit API check
     @Override
     public void stop() {
         if (mDelegateDrawable != null) {
-            //noinspection AndroidLintNewApi - Implicit when delegate is non-null.
             ((AnimatedVectorDrawable) mDelegateDrawable).stop();
             return;
         }
@@ -755,20 +766,19 @@
      */
     @RequiresApi(23)
     private static boolean unregisterPlatformCallback(AnimatedVectorDrawable dr,
-            Animatable2Compat.AnimationCallback callback) {
-        return dr.unregisterAnimationCallback(callback.getPlatformCallback());
+            AnimationCallback callback) {
+        return Api23Impl.unregisterAnimationCallback(dr, callback.getPlatformCallback());
     }
 
     @Override
-    public void registerAnimationCallback(@NonNull Animatable2Compat.AnimationCallback
-            callback) {
-        if (mDelegateDrawable != null) {
-            //noinspection AndroidLintNewApi - Implicit when delegate is non-null.
-            registerPlatformCallback((AnimatedVectorDrawable) mDelegateDrawable, callback);
+    public void registerAnimationCallback(@Nullable AnimationCallback callback) {
+        if (callback == null) {
             return;
         }
 
-        if (callback == null) {
+        if (mDelegateDrawable != null) {
+            //noinspection AndroidLintNewApi - Implicit when delegate is non-null.
+            registerPlatformCallback((AnimatedVectorDrawable) mDelegateDrawable, callback);
             return;
         }
 
@@ -790,7 +800,7 @@
             mAnimatorListener = new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationStart(Animator animation) {
-                    ArrayList<Animatable2Compat.AnimationCallback> tmpCallbacks =
+                    ArrayList<AnimationCallback> tmpCallbacks =
                             new ArrayList<>(mAnimationCallbacks);
                     int size = tmpCallbacks.size();
                     for (int i = 0; i < size; i++) {
@@ -800,7 +810,7 @@
 
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    ArrayList<Animatable2Compat.AnimationCallback> tmpCallbacks =
+                    ArrayList<AnimationCallback> tmpCallbacks =
                             new ArrayList<>(mAnimationCallbacks);
                     int size = tmpCallbacks.size();
                     for (int i = 0; i < size; i++) {
@@ -818,8 +828,8 @@
      */
     @RequiresApi(23)
     private static void registerPlatformCallback(@NonNull AnimatedVectorDrawable avd,
-            @NonNull final Animatable2Compat.AnimationCallback callback) {
-        avd.registerAnimationCallback(callback.getPlatformCallback());
+            @NonNull final AnimationCallback callback) {
+        Api23Impl.registerAnimationCallback(avd, callback.getPlatformCallback());
     }
 
     /**
@@ -833,14 +843,18 @@
     }
 
     @Override
-    public boolean unregisterAnimationCallback(
-            @NonNull Animatable2Compat.AnimationCallback callback) {
+    public boolean unregisterAnimationCallback(@Nullable AnimationCallback callback) {
+        if (callback == null) {
+            // Nothing to be removed.
+            return false;
+        }
+
         if (mDelegateDrawable != null) {
             //noinspection AndroidLintNewApi - Implicit when delegate is non-null.
             unregisterPlatformCallback((AnimatedVectorDrawable) mDelegateDrawable, callback);
         }
 
-        if (mAnimationCallbacks == null || callback == null) {
+        if (mAnimationCallbacks == null) {
             // Nothing to be removed.
             return false;
         }
@@ -853,11 +867,11 @@
         return removed;
     }
 
+    @SuppressLint("NewApi")
     @Override
     public void clearAnimationCallbacks() {
         if (mDelegateDrawable != null) {
-            //noinspection AndroidLintNewApi - Implicit when delegate is non-null.
-            ((AnimatedVectorDrawable) mDelegateDrawable).clearAnimationCallbacks();
+            Api23Impl.clearAnimationCallbacks(mDelegateDrawable);
             return;
         }
         removeAnimatorSetListener();
@@ -874,8 +888,8 @@
      * From API 24 on, the drawable is treated as an AnimatedVectorDrawable.
      * Otherwise, it is treated as AnimatedVectorDrawableCompat.
      */
-    public static void registerAnimationCallback(Drawable dr,
-            Animatable2Compat.AnimationCallback callback) {
+    public static void registerAnimationCallback(@Nullable Drawable dr,
+            @Nullable AnimationCallback callback) {
         if (dr == null || callback == null) {
             return;
         }
@@ -896,8 +910,8 @@
      * From API 24 on, the drawable is treated as an AnimatedVectorDrawable.
      * Otherwise, it is treated as AnimatedVectorDrawableCompat.
      */
-    public static boolean unregisterAnimationCallback(Drawable dr,
-            Animatable2Compat.AnimationCallback callback) {
+    public static boolean unregisterAnimationCallback(@Nullable Drawable dr,
+            @Nullable AnimationCallback callback) {
         if (dr == null || callback == null) {
             return false;
         }
@@ -918,15 +932,40 @@
      * From API 24 on, the drawable is treated as an AnimatedVectorDrawable.
      * Otherwise, it is treated as AnimatedVectorDrawableCompat.
      */
-    public static void clearAnimationCallbacks(Drawable dr) {
+    public static void clearAnimationCallbacks(@Nullable Drawable dr) {
         if (!(dr instanceof Animatable)) {
             return;
         }
         if (Build.VERSION.SDK_INT >= 24) {
-            ((AnimatedVectorDrawable) dr).clearAnimationCallbacks();
+            Api23Impl.clearAnimationCallbacks(dr);
         } else {
             ((AnimatedVectorDrawableCompat) dr).clearAnimationCallbacks();
         }
 
     }
+
+    @RequiresApi(23)
+    static class Api23Impl {
+        private Api23Impl() {
+            // This class is not instantiable.
+        }
+
+        @DoNotInline
+        static boolean unregisterAnimationCallback(Object animatedVectorDrawable,
+                Object callback) {
+            return ((AnimatedVectorDrawable) animatedVectorDrawable).unregisterAnimationCallback(
+                    (Animatable2.AnimationCallback) callback);
+        }
+
+        @DoNotInline
+        static void clearAnimationCallbacks(Object animatedVectorDrawable) {
+            ((AnimatedVectorDrawable) animatedVectorDrawable).clearAnimationCallbacks();
+        }
+
+        @DoNotInline
+        static void registerAnimationCallback(Object animatedVectorDrawable, Object callback) {
+            ((AnimatedVectorDrawable) animatedVectorDrawable).registerAnimationCallback(
+                    (Animatable2.AnimationCallback) callback);
+        }
+    }
 }
diff --git a/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/AnimationUtilsCompat.java b/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/AnimationUtilsCompat.java
index ec578fc..dbe3039 100644
--- a/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/AnimationUtilsCompat.java
+++ b/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/AnimationUtilsCompat.java
@@ -36,7 +36,10 @@
 import android.view.animation.LinearInterpolator;
 import android.view.animation.OvershootInterpolator;
 
+import androidx.annotation.AnimRes;
+import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
+import androidx.core.util.ObjectsCompat;
 import androidx.interpolator.view.animation.FastOutLinearInInterpolator;
 import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
 import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
@@ -59,11 +62,16 @@
      * @param id      The resource id of the animation to load
      * @return The animation object reference by the specified id
      */
-    public static Interpolator loadInterpolator(Context context, int id)
+    @SuppressWarnings("UnnecessaryInitCause") // requires API 24+
+    @NonNull
+    public static Interpolator loadInterpolator(@NonNull Context context, @AnimRes int id)
             throws NotFoundException {
         // From API 21, we added path Interpolator .
         if (Build.VERSION.SDK_INT >= 21) {
-            return AnimationUtils.loadInterpolator(context, id);
+            Interpolator interp = AnimationUtils.loadInterpolator(context, id);
+            ObjectsCompat.requireNonNull(interp, "Failed to parse interpolator, no start tag "
+                    + "found");
+            return interp;
         }
 
         XmlResourceParser parser = null;
@@ -94,9 +102,9 @@
 
     }
 
-    private static Interpolator createInterpolatorFromXml(Context context,
-            XmlPullParser parser)
-            throws XmlPullParserException, IOException {
+    @NonNull
+    private static Interpolator createInterpolatorFromXml(@NonNull Context context,
+            @NonNull XmlPullParser parser) throws XmlPullParserException, IOException {
 
         Interpolator interpolator = null;
 
@@ -115,30 +123,46 @@
 
             String name = parser.getName();
 
-            if (name.equals("linearInterpolator")) {
-                interpolator = new LinearInterpolator();
-            } else if (name.equals("accelerateInterpolator")) {
-                interpolator = new AccelerateInterpolator(context, attrs);
-            } else if (name.equals("decelerateInterpolator")) {
-                interpolator = new DecelerateInterpolator(context, attrs);
-            } else if (name.equals("accelerateDecelerateInterpolator")) {
-                interpolator = new AccelerateDecelerateInterpolator();
-            } else if (name.equals("cycleInterpolator")) {
-                interpolator = new CycleInterpolator(context, attrs);
-            } else if (name.equals("anticipateInterpolator")) {
-                interpolator = new AnticipateInterpolator(context, attrs);
-            } else if (name.equals("overshootInterpolator")) {
-                interpolator = new OvershootInterpolator(context, attrs);
-            } else if (name.equals("anticipateOvershootInterpolator")) {
-                interpolator = new AnticipateOvershootInterpolator(context, attrs);
-            } else if (name.equals("bounceInterpolator")) {
-                interpolator = new BounceInterpolator();
-            } else if (name.equals("pathInterpolator")) {
-                interpolator = new PathInterpolatorCompat(context, attrs, parser);
-            } else {
-                throw new RuntimeException("Unknown interpolator name: " + parser.getName());
+            switch (name) {
+                case "linearInterpolator":
+                    interpolator = new LinearInterpolator();
+                    break;
+                case "accelerateInterpolator":
+                    interpolator = new AccelerateInterpolator(context, attrs);
+                    break;
+                case "decelerateInterpolator":
+                    interpolator = new DecelerateInterpolator(context, attrs);
+                    break;
+                case "accelerateDecelerateInterpolator":
+                    interpolator = new AccelerateDecelerateInterpolator();
+                    break;
+                case "cycleInterpolator":
+                    interpolator = new CycleInterpolator(context, attrs);
+                    break;
+                case "anticipateInterpolator":
+                    interpolator = new AnticipateInterpolator(context, attrs);
+                    break;
+                case "overshootInterpolator":
+                    interpolator = new OvershootInterpolator(context, attrs);
+                    break;
+                case "anticipateOvershootInterpolator":
+                    interpolator = new AnticipateOvershootInterpolator(context, attrs);
+                    break;
+                case "bounceInterpolator":
+                    interpolator = new BounceInterpolator();
+                    break;
+                case "pathInterpolator":
+                    interpolator = new PathInterpolatorCompat(context, attrs, parser);
+                    break;
+                default:
+                    throw new RuntimeException("Unknown interpolator name: " + parser.getName());
             }
         }
+
+        if (interpolator == null) {
+            throw new RuntimeException("Failed to parse interpolator, no start tag found");
+        }
+
         return interpolator;
     }
 
diff --git a/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/ArgbEvaluator.java b/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/ArgbEvaluator.java
index 793659e..73e0b63 100644
--- a/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/ArgbEvaluator.java
+++ b/vectordrawable/vectordrawable-animated/src/main/java/androidx/vectordrawable/graphics/drawable/ArgbEvaluator.java
@@ -21,6 +21,7 @@
 import android.animation.TypeEvaluator;
 import android.animation.ValueAnimator;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 
 /**
@@ -29,7 +30,7 @@
  * @hide
  */
 @RestrictTo(LIBRARY_GROUP_PREFIX)
-public class ArgbEvaluator implements TypeEvaluator {
+public class ArgbEvaluator implements TypeEvaluator<Object> {
     private static final ArgbEvaluator sInstance = new ArgbEvaluator();
 
     /**
@@ -39,6 +40,7 @@
      *
      * @return An instance of <code>ArgbEvalutor</code>.
      */
+    @NonNull
     public static ArgbEvaluator getInstance() {
         return sInstance;
     }
diff --git a/vectordrawable/vectordrawable/api/1.2.0-beta02.txt b/vectordrawable/vectordrawable/api/1.2.0-beta02.txt
index 5a6c00b..0285c8e 100644
--- a/vectordrawable/vectordrawable/api/1.2.0-beta02.txt
+++ b/vectordrawable/vectordrawable/api/1.2.0-beta02.txt
@@ -3,11 +3,11 @@
 
   public class VectorDrawableCompat extends android.graphics.drawable.Drawable {
     method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat? create(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?);
-    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat! createFromXmlInner(android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
   }
 
diff --git a/vectordrawable/vectordrawable/api/current.txt b/vectordrawable/vectordrawable/api/current.txt
index 5a6c00b..0285c8e 100644
--- a/vectordrawable/vectordrawable/api/current.txt
+++ b/vectordrawable/vectordrawable/api/current.txt
@@ -3,11 +3,11 @@
 
   public class VectorDrawableCompat extends android.graphics.drawable.Drawable {
     method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat? create(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?);
-    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat! createFromXmlInner(android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
   }
 
diff --git a/vectordrawable/vectordrawable/api/public_plus_experimental_1.2.0-beta02.txt b/vectordrawable/vectordrawable/api/public_plus_experimental_1.2.0-beta02.txt
index 5a6c00b..0285c8e 100644
--- a/vectordrawable/vectordrawable/api/public_plus_experimental_1.2.0-beta02.txt
+++ b/vectordrawable/vectordrawable/api/public_plus_experimental_1.2.0-beta02.txt
@@ -3,11 +3,11 @@
 
   public class VectorDrawableCompat extends android.graphics.drawable.Drawable {
     method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat? create(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?);
-    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat! createFromXmlInner(android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
   }
 
diff --git a/vectordrawable/vectordrawable/api/public_plus_experimental_current.txt b/vectordrawable/vectordrawable/api/public_plus_experimental_current.txt
index 5a6c00b..0285c8e 100644
--- a/vectordrawable/vectordrawable/api/public_plus_experimental_current.txt
+++ b/vectordrawable/vectordrawable/api/public_plus_experimental_current.txt
@@ -3,11 +3,11 @@
 
   public class VectorDrawableCompat extends android.graphics.drawable.Drawable {
     method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat? create(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?);
-    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat! createFromXmlInner(android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
   }
 
diff --git a/vectordrawable/vectordrawable/api/restricted_1.2.0-beta02.txt b/vectordrawable/vectordrawable/api/restricted_1.2.0-beta02.txt
index 30d66c1..89a2875 100644
--- a/vectordrawable/vectordrawable/api/restricted_1.2.0-beta02.txt
+++ b/vectordrawable/vectordrawable/api/restricted_1.2.0-beta02.txt
@@ -3,12 +3,12 @@
 
   public class VectorDrawableCompat extends android.graphics.drawable.Drawable implements androidx.core.graphics.drawable.TintAwareDrawable {
     method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat? create(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?);
-    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat! createFromXmlInner(android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public float getPixelSize();
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
   }
 
diff --git a/vectordrawable/vectordrawable/api/restricted_current.txt b/vectordrawable/vectordrawable/api/restricted_current.txt
index 30d66c1..89a2875 100644
--- a/vectordrawable/vectordrawable/api/restricted_current.txt
+++ b/vectordrawable/vectordrawable/api/restricted_current.txt
@@ -3,12 +3,12 @@
 
   public class VectorDrawableCompat extends android.graphics.drawable.Drawable implements androidx.core.graphics.drawable.TintAwareDrawable {
     method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat? create(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?);
-    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat! createFromXmlInner(android.content.res.Resources!, org.xmlpull.v1.XmlPullParser!, android.util.AttributeSet!, android.content.res.Resources.Theme!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void draw(android.graphics.Canvas!);
+    method public static androidx.vectordrawable.graphics.drawable.VectorDrawableCompat createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public float getPixelSize();
     method public void setAlpha(int);
-    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setColorFilter(android.graphics.ColorFilter?);
     method public void setColorFilter(int, android.graphics.PorterDuff.Mode!);
   }
 
diff --git a/vectordrawable/vectordrawable/build.gradle b/vectordrawable/vectordrawable/build.gradle
index 8e6ae22..b345be1 100644
--- a/vectordrawable/vectordrawable/build.gradle
+++ b/vectordrawable/vectordrawable/build.gradle
@@ -7,7 +7,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.6.0")
     implementation("androidx.collection:collection:1.1.0")
 
     androidTestImplementation(libs.testExtJunit)
diff --git a/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/AndroidResources.java b/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/AndroidResources.java
index a66fa2e..b76c700 100644
--- a/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/AndroidResources.java
+++ b/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/AndroidResources.java
@@ -16,8 +16,11 @@
 
 package androidx.vectordrawable.graphics.drawable;
 
+import android.annotation.SuppressLint;
+
 import androidx.annotation.StyleableRes;
 
+@SuppressLint("ResourceType") // We're doing something non-standard but correct.
 class AndroidResources {
 
     // Resources ID generated in the latest R.java for framework.
@@ -69,6 +72,8 @@
     static final int STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_OFFSET = 7;
     static final int STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_START = 5;
     static final int STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_FILLTYPE = 13;
+
+    @StyleableRes
     static final int[] STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH = {
             android.R.attr.name, android.R.attr.pathData, android.R.attr.fillType
     };
@@ -76,10 +81,13 @@
     static final int STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH_PATH_DATA = 1;
     static final int STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH_FILLTYPE = 2;
 
+    @StyleableRes
     static final int[] STYLEABLE_ANIMATED_VECTOR_DRAWABLE = {
             android.R.attr.drawable
     };
     static final int STYLEABLE_ANIMATED_VECTOR_DRAWABLE_DRAWABLE = 0;
+
+    @StyleableRes
     static final int[] STYLEABLE_ANIMATED_VECTOR_DRAWABLE_TARGET = {
             android.R.attr.name, android.R.attr.animation
     };
@@ -121,6 +129,7 @@
     };
     public static final int STYLEABLE_KEYFRAME_VALUE = 0;
     public static final int STYLEABLE_KEYFRAME_INTERPOLATOR = 1;
+    @SuppressWarnings("unused")
     public static final int STYLEABLE_KEYFRAME_VALUE_TYPE = 2;
     public static final int STYLEABLE_KEYFRAME_FRACTION = 3;
 
diff --git a/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCommon.java b/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCommon.java
index ec3cf92..d6b87af 100644
--- a/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCommon.java
+++ b/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCommon.java
@@ -22,6 +22,7 @@
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
 
+import androidx.annotation.NonNull;
 import androidx.core.graphics.drawable.DrawableCompat;
 import androidx.core.graphics.drawable.TintAwareDrawable;
 
@@ -64,14 +65,12 @@
         if (mDelegateDrawable != null) {
             DrawableCompat.setHotspot(mDelegateDrawable, x, y);
         }
-        return;
     }
 
     @Override
     public void setHotspotBounds(int left, int top, int right, int bottom) {
         if (mDelegateDrawable != null) {
             DrawableCompat.setHotspotBounds(mDelegateDrawable, left, top, right, bottom);
-            return;
         }
     }
 
@@ -79,24 +78,22 @@
     public void setFilterBitmap(boolean filter) {
         if (mDelegateDrawable != null) {
             mDelegateDrawable.setFilterBitmap(filter);
-            return;
         }
     }
 
+    @SuppressWarnings("deprecation")
     @Override
     public void jumpToCurrentState() {
         if (mDelegateDrawable != null) {
             DrawableCompat.jumpToCurrentState(mDelegateDrawable);
-            return;
         }
     }
 
     @Override
-    public void applyTheme(Resources.Theme t) {
+    public void applyTheme(@NonNull Resources.Theme t) {
         // API >= 21 only.
         if (mDelegateDrawable != null) {
             DrawableCompat.applyTheme(mDelegateDrawable, t);
-            return;
         }
     }
 
diff --git a/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCompat.java b/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCompat.java
index ddde6ed..566ad9d 100644
--- a/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCompat.java
+++ b/vectordrawable/vectordrawable/src/main/java/androidx/vectordrawable/graphics/drawable/VectorDrawableCompat.java
@@ -325,6 +325,7 @@
         mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
     }
 
+    @NonNull
     @Override
     public Drawable mutate() {
         if (mDelegateDrawable != null) {
@@ -343,6 +344,7 @@
         return mVectorState.mVPathRenderer.mVGTargetsMap.get(name);
     }
 
+    @NonNull
     @Override
     public ConstantState getConstantState() {
         if (mDelegateDrawable != null && Build.VERSION.SDK_INT >= 24) {
@@ -354,7 +356,7 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
+    public void draw(@NonNull Canvas canvas) {
         if (mDelegateDrawable != null) {
             mDelegateDrawable.draw(canvas);
             return;
@@ -448,7 +450,7 @@
     }
 
     @Override
-    public void setColorFilter(ColorFilter colorFilter) {
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
         if (mDelegateDrawable != null) {
             mDelegateDrawable.setColorFilter(colorFilter);
             return;
@@ -458,6 +460,7 @@
         invalidateSelf();
     }
 
+    @Nullable
     @Override
     public ColorFilter getColorFilter() {
         if (mDelegateDrawable != null) {
@@ -470,6 +473,7 @@
      * Ensures the tint filter is consistent with the current tint color and
      * mode.
      */
+    @SuppressWarnings("unused")
     PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint,
                                            PorterDuff.Mode tintMode) {
         if (tint == null || tintMode == null) {
@@ -492,7 +496,7 @@
     }
 
     @Override
-    public void setTintList(ColorStateList tint) {
+    public void setTintList(@Nullable ColorStateList tint) {
         if (mDelegateDrawable != null) {
             DrawableCompat.setTintList(mDelegateDrawable, tint);
             return;
@@ -507,7 +511,7 @@
     }
 
     @Override
-    public void setTintMode(Mode tintMode) {
+    public void setTintMode(@Nullable Mode tintMode) {
         if (mDelegateDrawable != null) {
             DrawableCompat.setTintMode(mDelegateDrawable, tintMode);
             return;
@@ -611,6 +615,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("unused")
     @RestrictTo(LIBRARY_GROUP_PREFIX)
     public float getPixelSize() {
         if (mVectorState == null || mVectorState.mVPathRenderer == null
@@ -657,6 +662,7 @@
             @SuppressLint("ResourceType") final XmlPullParser parser = res.getXml(resId);
             final AttributeSet attrs = Xml.asAttributeSet(parser);
             int type;
+            //noinspection StatementWithEmptyBody
             while ((type = parser.next()) != XmlPullParser.START_TAG
                     && type != XmlPullParser.END_DOCUMENT) {
                 // Empty loop
@@ -679,8 +685,10 @@
      * document, tries to create a Drawable from that tag. Returns {@code null}
      * if the tag is not a valid drawable.
      */
-    public static VectorDrawableCompat createFromXmlInner(Resources r, XmlPullParser parser,
-            AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException {
+    @NonNull
+    public static VectorDrawableCompat createFromXmlInner(@NonNull Resources r,
+            @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
         final VectorDrawableCompat drawable = new VectorDrawableCompat();
         drawable.inflate(r, parser, attrs, theme);
         return drawable;
@@ -694,8 +702,8 @@
     }
 
     @Override
-    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs)
-            throws XmlPullParserException, IOException {
+    public void inflate(@NonNull Resources res, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs) throws XmlPullParserException, IOException {
         if (mDelegateDrawable != null) {
             mDelegateDrawable.inflate(res, parser, attrs);
             return;
@@ -705,7 +713,8 @@
     }
 
     @Override
-    public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+    public void inflate(@NonNull Resources res, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         if (mDelegateDrawable != null) {
             DrawableCompat.inflate(mDelegateDrawable, res, parser, attrs, theme);
@@ -713,8 +722,7 @@
         }
 
         final VectorDrawableCompatState state = mVectorState;
-        final VPathRenderer pathRenderer = new VPathRenderer();
-        state.mVPathRenderer = pathRenderer;
+        state.mVPathRenderer = new VPathRenderer();
 
         final TypedArray a = TypedArrayUtils.obtainAttributes(res, theme, attrs,
                 AndroidResources.STYLEABLE_VECTOR_DRAWABLE_TYPE_ARRAY);
@@ -733,6 +741,7 @@
      * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
      * attribute's enum value.
      */
+    @SuppressWarnings("SameParameterValue")
     private static PorterDuff.Mode parseTintModeCompat(int value, Mode defaultMode) {
         switch (value) {
             case 3:
@@ -834,33 +843,35 @@
             if (eventType == XmlPullParser.START_TAG) {
                 final String tagName = parser.getName();
                 final VGroup currentGroup = groupStack.peek();
-                if (SHAPE_PATH.equals(tagName)) {
-                    final VFullPath path = new VFullPath();
-                    path.inflate(res, attrs, theme, parser);
-                    currentGroup.mChildren.add(path);
-                    if (path.getPathName() != null) {
-                        pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+                if (currentGroup != null) {
+                    if (SHAPE_PATH.equals(tagName)) {
+                        final VFullPath path = new VFullPath();
+                        path.inflate(res, attrs, theme, parser);
+                        currentGroup.mChildren.add(path);
+                        if (path.getPathName() != null) {
+                            pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+                        }
+                        noPathTag = false;
+                        state.mChangingConfigurations |= path.mChangingConfigurations;
+                    } else if (SHAPE_CLIP_PATH.equals(tagName)) {
+                        final VClipPath path = new VClipPath();
+                        path.inflate(res, attrs, theme, parser);
+                        currentGroup.mChildren.add(path);
+                        if (path.getPathName() != null) {
+                            pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+                        }
+                        state.mChangingConfigurations |= path.mChangingConfigurations;
+                    } else if (SHAPE_GROUP.equals(tagName)) {
+                        VGroup newChildGroup = new VGroup();
+                        newChildGroup.inflate(res, attrs, theme, parser);
+                        currentGroup.mChildren.add(newChildGroup);
+                        groupStack.push(newChildGroup);
+                        if (newChildGroup.getGroupName() != null) {
+                            pathRenderer.mVGTargetsMap.put(newChildGroup.getGroupName(),
+                                    newChildGroup);
+                        }
+                        state.mChangingConfigurations |= newChildGroup.mChangingConfigurations;
                     }
-                    noPathTag = false;
-                    state.mChangingConfigurations |= path.mChangingConfigurations;
-                } else if (SHAPE_CLIP_PATH.equals(tagName)) {
-                    final VClipPath path = new VClipPath();
-                    path.inflate(res, attrs, theme, parser);
-                    currentGroup.mChildren.add(path);
-                    if (path.getPathName() != null) {
-                        pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
-                    }
-                    state.mChangingConfigurations |= path.mChangingConfigurations;
-                } else if (SHAPE_GROUP.equals(tagName)) {
-                    VGroup newChildGroup = new VGroup();
-                    newChildGroup.inflate(res, attrs, theme, parser);
-                    currentGroup.mChildren.add(newChildGroup);
-                    groupStack.push(newChildGroup);
-                    if (newChildGroup.getGroupName() != null) {
-                        pathRenderer.mVGTargetsMap.put(newChildGroup.getGroupName(),
-                                newChildGroup);
-                    }
-                    state.mChangingConfigurations |= newChildGroup.mChangingConfigurations;
                 }
             } else if (eventType == XmlPullParser.END_TAG) {
                 final String tagName = parser.getName();
@@ -882,9 +893,9 @@
     }
 
     private void printGroupTree(VGroup currentGroup, int level) {
-        String indent = "";
+        StringBuilder indent = new StringBuilder();
         for (int i = 0; i < level; i++) {
-            indent += "    ";
+            indent.append("    ");
         }
         // Print the current node
         Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName()
@@ -901,6 +912,7 @@
         }
     }
 
+    @SuppressWarnings("SameParameterValue")
     void setAllowCaching(boolean allowCaching) {
         mAllowCaching = allowCaching;
     }
@@ -941,7 +953,7 @@
     }
 
     @Override
-    public void scheduleSelf(Runnable what, long when) {
+    public void scheduleSelf(@NonNull Runnable what, long when) {
         if (mDelegateDrawable != null) {
             mDelegateDrawable.scheduleSelf(what, when);
             return;
@@ -958,7 +970,7 @@
     }
 
     @Override
-    public void unscheduleSelf(Runnable what) {
+    public void unscheduleSelf(@NonNull Runnable what) {
         if (mDelegateDrawable != null) {
             mDelegateDrawable.unscheduleSelf(what);
             return;
@@ -1019,7 +1031,9 @@
         Mode mTintMode = DEFAULT_TINT_MODE;
         boolean mAutoMirrored;
 
+        // Cached fields, don't copy on mutate.
         Bitmap mCachedBitmap;
+        @SuppressWarnings("unused")
         int[] mCachedThemeAttrs;
         ColorStateList mCachedTint;
         Mode mCachedTintMode;
@@ -1033,6 +1047,7 @@
         Paint mTempPaint;
 
         // Deep copy for mutate() or implicitly mutate.
+        @SuppressWarnings("CopyConstructorMissesField") // Intentional, see field comments.
         VectorDrawableCompatState(VectorDrawableCompatState copy) {
             if (copy != null) {
                 mChangingConfigurations = copy.mChangingConfigurations;
@@ -1093,22 +1108,16 @@
         }
 
         public boolean canReuseBitmap(int width, int height) {
-            if (width == mCachedBitmap.getWidth()
-                    && height == mCachedBitmap.getHeight()) {
-                return true;
-            }
-            return false;
+            return width == mCachedBitmap.getWidth()
+                    && height == mCachedBitmap.getHeight();
         }
 
         public boolean canReuseCache() {
-            if (!mCacheDirty
+            return !mCacheDirty
                     && mCachedTint == mTint
                     && mCachedTintMode == mTintMode
                     && mCachedAutoMirrored == mAutoMirrored
-                    && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) {
-                return true;
-            }
-            return false;
+                    && mCachedRootAlpha == mVPathRenderer.getRootAlpha();
         }
 
         public void updateCacheStates() {
@@ -1189,7 +1198,7 @@
         String mRootName = null;
         Boolean mIsStateful = null;
 
-        final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
+        final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
 
         VPathRenderer() {
             mRootGroup = new VGroup();
@@ -1216,6 +1225,7 @@
             return getRootAlpha() / 255.0f;
         }
 
+        @SuppressWarnings("CopyConstructorMissesField")
         VPathRenderer(VPathRenderer copy) {
             mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
             mPath = new Path(copy.mPath);
@@ -1328,6 +1338,8 @@
                     final Paint fillPaint = mFillPaint;
                     if (fill.isGradient()) {
                         final Shader shader = fill.getShader();
+                        // isGradient() implies non-null shader
+                        //noinspection ConstantConditions
                         shader.setLocalMatrix(mFinalPathMatrix);
                         fillPaint.setShader(shader);
                         fillPaint.setAlpha(Math.round(fullPath.mFillAlpha * 255f));
@@ -1361,6 +1373,8 @@
                     strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
                     if (strokeColor.isGradient()) {
                         final Shader shader = strokeColor.getShader();
+                        // isGradient() implies non-null shader
+                        //noinspection ConstantConditions
                         shader.setLocalMatrix(mFinalPathMatrix);
                         strokePaint.setShader(shader);
                         strokePaint.setAlpha(Math.round(fullPath.mStrokeAlpha * 255f));
@@ -1698,9 +1712,9 @@
         }
 
         public void printVPath(int level) {
-            String indent = "";
+            StringBuilder indent = new StringBuilder();
             for (int i = 0; i < level; i++) {
-                indent += "    ";
+                indent.append("    ");
             }
             Log.v(LOGTAG, indent + "current path is :" + mPathName
                     + " pathData is " + nodesToString(mNodes));
@@ -1708,17 +1722,18 @@
         }
 
         public String nodesToString(PathParser.PathDataNode[] nodes) {
-            String result = " ";
-            for (int i = 0; i < nodes.length; i++) {
-                result += nodes[i].mType + ":";
-                float[] params = nodes[i].mParams;
-                for (int j = 0; j < params.length; j++) {
-                    result += params[j] + ",";
+            StringBuilder result = new StringBuilder(" ");
+            for (PathParser.PathDataNode node : nodes) {
+                result.append(node.mType).append(":");
+                float[] params = node.mParams;
+                for (float param : params) {
+                    result.append(param).append(",");
                 }
             }
-            return result;
+            return result.toString();
         }
 
+        @SuppressWarnings("CopyConstructorMissesField")
         VPath(VPath copy) {
             mPathName = copy.mPathName;
             mChangingConfigurations = copy.mChangingConfigurations;
@@ -1736,10 +1751,12 @@
             return mPathName;
         }
 
+        @SuppressWarnings("unused")
         public boolean canApplyTheme() {
             return false;
         }
 
+        @SuppressWarnings("unused")
         public void applyTheme(Theme t) {
         }
 
@@ -1972,10 +1989,6 @@
 
         @Override
         public void applyTheme(Theme t) {
-            if (mThemeAttrs == null) {
-                return;
-            }
-
             /*
              * TODO TINT THEME Not supported yet final TypedArray a =
              * t.resolveAttributes(mThemeAttrs, styleable_VectorDrawablePath);
diff --git a/versionedparcelable/versionedparcelable-compiler/lint-baseline.xml b/versionedparcelable/versionedparcelable-compiler/lint-baseline.xml
index 2798d27..4c6df9f 100644
--- a/versionedparcelable/versionedparcelable-compiler/lint-baseline.xml
+++ b/versionedparcelable/versionedparcelable-compiler/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="cli" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="BanSynchronizedMethods"
@@ -7,7 +7,9 @@
         errorLine1="    @Override"
         errorLine2="    ^">
         <location
-            file="src/main/java/androidx/versionedparcelable/compiler/VersionedParcelProcessor.java"/>
+            file="src/main/java/androidx/versionedparcelable/compiler/VersionedParcelProcessor.java"
+            line="85"
+            column="5"/>
     </issue>
 
 </issues>
diff --git a/versionedparcelable/versionedparcelable/lint-baseline.xml b/versionedparcelable/versionedparcelable/lint-baseline.xml
index 63ec5bb..ae680c9 100644
--- a/versionedparcelable/versionedparcelable/lint-baseline.xml
+++ b/versionedparcelable/versionedparcelable/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="BanUncheckedReflection"
diff --git a/viewpager2/viewpager2/lint-baseline.xml b/viewpager2/viewpager2/lint-baseline.xml
deleted file mode 100644
index 1de0138..0000000
--- a/viewpager2/viewpager2/lint-baseline.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 19 (current min is 14): `java.lang.AssertionError()`"
-        errorLine1="                throw AssertionError(&quot;Block hit bad state $n times&quot;, e)"
-        errorLine2="                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 16 (current min is 14): `android.view.View#setHasTransientState`"
-        errorLine1="                v.setHasTransientState(true)"
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/viewpager2/widget/TransientStateFragmentTest.kt"/>
-    </issue>
-
-    <issue
-        id="WrongConstant"
-        message="Must be one of: ViewPager2.ORIENTATION_HORIZONTAL, ViewPager2.ORIENTATION_VERTICAL"
-        errorLine1="        return mLayoutManager.getOrientation();"
-        errorLine2="               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/viewpager2/widget/ViewPager2.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 21; however, the containing class androidx.viewpager2.widget.ViewPager2 is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="        super(context, attrs, defStyleAttr, defStyleRes);"
-        errorLine2="        ~~~~~">
-        <location
-            file="src/main/java/androidx/viewpager2/widget/ViewPager2.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 24; however, the containing class androidx.viewpager2.widget.ViewPager2.SavedState is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            super(source, loader);"
-        errorLine2="            ~~~~~">
-        <location
-            file="src/main/java/androidx/viewpager2/widget/ViewPager2.java"/>
-    </issue>
-
-</issues>
diff --git a/wear/tiles/tiles-material/api/current.txt b/wear/tiles/tiles-material/api/current.txt
index 65c6fe2..aecb80e 100644
--- a/wear/tiles/tiles-material/api/current.txt
+++ b/wear/tiles/tiles-material/api/current.txt
@@ -40,11 +40,11 @@
   public class ButtonDefaults {
     method public static androidx.wear.tiles.DimensionBuilders.DpProp recommendedIconSize(androidx.wear.tiles.DimensionBuilders.DpProp);
     method public static androidx.wear.tiles.DimensionBuilders.DpProp recommendedIconSize(@Dimension(unit=androidx.annotation.Dimension.DP) float);
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_BUTTON_SIZE;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp EXTRA_LARGE_BUTTON_SIZE;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp LARGE_BUTTON_SIZE;
-    field public static final androidx.wear.tiles.material.ButtonColors PRIMARY_BUTTON_COLORS;
-    field public static final androidx.wear.tiles.material.ButtonColors SECONDARY_BUTTON_COLORS;
+    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_SIZE;
+    field public static final androidx.wear.tiles.DimensionBuilders.DpProp EXTRA_LARGE_SIZE;
+    field public static final androidx.wear.tiles.DimensionBuilders.DpProp LARGE_SIZE;
+    field public static final androidx.wear.tiles.material.ButtonColors PRIMARY_COLORS;
+    field public static final androidx.wear.tiles.material.ButtonColors SECONDARY_COLORS;
   }
 
   public class Chip implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
@@ -56,8 +56,8 @@
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
     method public int getHorizontalAlignment();
     method public String? getIconContent();
-    method public String? getLabelContent();
-    method public String? getPrimaryTextContent();
+    method public String? getPrimaryLabelContent();
+    method public String? getSecondaryLabelContent();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
   }
 
@@ -68,10 +68,9 @@
     method public androidx.wear.tiles.material.Chip.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.Chip.Builder setCustomContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     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 setIconContent(String);
+    method public androidx.wear.tiles.material.Chip.Builder setPrimaryLabelContent(String);
+    method public androidx.wear.tiles.material.Chip.Builder setSecondaryLabelContent(String);
     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);
   }
@@ -223,12 +222,29 @@
 
 package androidx.wear.tiles.material.layouts {
 
+  public class EdgeContentLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
+    method public static androidx.wear.tiles.material.layouts.EdgeContentLayout? fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getContent();
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getEdgeContent();
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getPrimaryLabelTextContent();
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getSecondaryLabelTextContent();
+  }
+
+  public static final class EdgeContentLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
+    ctor public EdgeContentLayout.Builder(androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout build();
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setEdgeContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setPrimaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setSecondaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+  }
+
   public class LayoutDefaults {
     field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_VERTICAL_SPACER_HEIGHT;
+    field public static final float EDGE_CONTENT_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP = 6.0f;
+    field public static final float EDGE_CONTENT_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP = 8.0f;
     field public static final int MULTI_BUTTON_MAX_NUMBER = 7; // 0x7
     field public static final androidx.wear.tiles.DimensionBuilders.DpProp MULTI_SLOT_LAYOUT_HORIZONTAL_SPACER_WIDTH;
-    field public static final float PROGRESS_INDICATOR_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP = 6.0f;
-    field public static final float PROGRESS_INDICATOR_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP = 8.0f;
   }
 
   public class MultiButtonLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
@@ -278,22 +294,5 @@
     method public androidx.wear.tiles.material.layouts.PrimaryLayout.Builder setVerticalSpacerHeight(@Dimension(unit=androidx.annotation.Dimension.DP) float);
   }
 
-  public class ProgressIndicatorLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
-    method public static androidx.wear.tiles.material.layouts.ProgressIndicatorLayout? fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getPrimaryLabelTextContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getProgressIndicatorContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getSecondaryLabelTextContent();
-  }
-
-  public static final class ProgressIndicatorLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
-    ctor public ProgressIndicatorLayout.Builder(androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout build();
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setPrimaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setProgressIndicatorContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setSecondaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-  }
-
 }
 
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 65c6fe2..aecb80e 100644
--- a/wear/tiles/tiles-material/api/public_plus_experimental_current.txt
+++ b/wear/tiles/tiles-material/api/public_plus_experimental_current.txt
@@ -40,11 +40,11 @@
   public class ButtonDefaults {
     method public static androidx.wear.tiles.DimensionBuilders.DpProp recommendedIconSize(androidx.wear.tiles.DimensionBuilders.DpProp);
     method public static androidx.wear.tiles.DimensionBuilders.DpProp recommendedIconSize(@Dimension(unit=androidx.annotation.Dimension.DP) float);
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_BUTTON_SIZE;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp EXTRA_LARGE_BUTTON_SIZE;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp LARGE_BUTTON_SIZE;
-    field public static final androidx.wear.tiles.material.ButtonColors PRIMARY_BUTTON_COLORS;
-    field public static final androidx.wear.tiles.material.ButtonColors SECONDARY_BUTTON_COLORS;
+    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_SIZE;
+    field public static final androidx.wear.tiles.DimensionBuilders.DpProp EXTRA_LARGE_SIZE;
+    field public static final androidx.wear.tiles.DimensionBuilders.DpProp LARGE_SIZE;
+    field public static final androidx.wear.tiles.material.ButtonColors PRIMARY_COLORS;
+    field public static final androidx.wear.tiles.material.ButtonColors SECONDARY_COLORS;
   }
 
   public class Chip implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
@@ -56,8 +56,8 @@
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
     method public int getHorizontalAlignment();
     method public String? getIconContent();
-    method public String? getLabelContent();
-    method public String? getPrimaryTextContent();
+    method public String? getPrimaryLabelContent();
+    method public String? getSecondaryLabelContent();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
   }
 
@@ -68,10 +68,9 @@
     method public androidx.wear.tiles.material.Chip.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.Chip.Builder setCustomContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     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 setIconContent(String);
+    method public androidx.wear.tiles.material.Chip.Builder setPrimaryLabelContent(String);
+    method public androidx.wear.tiles.material.Chip.Builder setSecondaryLabelContent(String);
     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);
   }
@@ -223,12 +222,29 @@
 
 package androidx.wear.tiles.material.layouts {
 
+  public class EdgeContentLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
+    method public static androidx.wear.tiles.material.layouts.EdgeContentLayout? fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getContent();
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getEdgeContent();
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getPrimaryLabelTextContent();
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getSecondaryLabelTextContent();
+  }
+
+  public static final class EdgeContentLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
+    ctor public EdgeContentLayout.Builder(androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout build();
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setEdgeContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setPrimaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setSecondaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+  }
+
   public class LayoutDefaults {
     field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_VERTICAL_SPACER_HEIGHT;
+    field public static final float EDGE_CONTENT_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP = 6.0f;
+    field public static final float EDGE_CONTENT_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP = 8.0f;
     field public static final int MULTI_BUTTON_MAX_NUMBER = 7; // 0x7
     field public static final androidx.wear.tiles.DimensionBuilders.DpProp MULTI_SLOT_LAYOUT_HORIZONTAL_SPACER_WIDTH;
-    field public static final float PROGRESS_INDICATOR_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP = 6.0f;
-    field public static final float PROGRESS_INDICATOR_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP = 8.0f;
   }
 
   public class MultiButtonLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
@@ -278,22 +294,5 @@
     method public androidx.wear.tiles.material.layouts.PrimaryLayout.Builder setVerticalSpacerHeight(@Dimension(unit=androidx.annotation.Dimension.DP) float);
   }
 
-  public class ProgressIndicatorLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
-    method public static androidx.wear.tiles.material.layouts.ProgressIndicatorLayout? fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getPrimaryLabelTextContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getProgressIndicatorContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getSecondaryLabelTextContent();
-  }
-
-  public static final class ProgressIndicatorLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
-    ctor public ProgressIndicatorLayout.Builder(androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout build();
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setPrimaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setProgressIndicatorContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setSecondaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-  }
-
 }
 
diff --git a/wear/tiles/tiles-material/api/restricted_current.txt b/wear/tiles/tiles-material/api/restricted_current.txt
index 65c6fe2..aecb80e 100644
--- a/wear/tiles/tiles-material/api/restricted_current.txt
+++ b/wear/tiles/tiles-material/api/restricted_current.txt
@@ -40,11 +40,11 @@
   public class ButtonDefaults {
     method public static androidx.wear.tiles.DimensionBuilders.DpProp recommendedIconSize(androidx.wear.tiles.DimensionBuilders.DpProp);
     method public static androidx.wear.tiles.DimensionBuilders.DpProp recommendedIconSize(@Dimension(unit=androidx.annotation.Dimension.DP) float);
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_BUTTON_SIZE;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp EXTRA_LARGE_BUTTON_SIZE;
-    field public static final androidx.wear.tiles.DimensionBuilders.DpProp LARGE_BUTTON_SIZE;
-    field public static final androidx.wear.tiles.material.ButtonColors PRIMARY_BUTTON_COLORS;
-    field public static final androidx.wear.tiles.material.ButtonColors SECONDARY_BUTTON_COLORS;
+    field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_SIZE;
+    field public static final androidx.wear.tiles.DimensionBuilders.DpProp EXTRA_LARGE_SIZE;
+    field public static final androidx.wear.tiles.DimensionBuilders.DpProp LARGE_SIZE;
+    field public static final androidx.wear.tiles.material.ButtonColors PRIMARY_COLORS;
+    field public static final androidx.wear.tiles.material.ButtonColors SECONDARY_COLORS;
   }
 
   public class Chip implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
@@ -56,8 +56,8 @@
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getHeight();
     method public int getHorizontalAlignment();
     method public String? getIconContent();
-    method public String? getLabelContent();
-    method public String? getPrimaryTextContent();
+    method public String? getPrimaryLabelContent();
+    method public String? getSecondaryLabelContent();
     method public androidx.wear.tiles.DimensionBuilders.ContainerDimension getWidth();
   }
 
@@ -68,10 +68,9 @@
     method public androidx.wear.tiles.material.Chip.Builder setContentDescription(CharSequence);
     method public androidx.wear.tiles.material.Chip.Builder setCustomContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
     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 setIconContent(String);
+    method public androidx.wear.tiles.material.Chip.Builder setPrimaryLabelContent(String);
+    method public androidx.wear.tiles.material.Chip.Builder setSecondaryLabelContent(String);
     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);
   }
@@ -223,12 +222,29 @@
 
 package androidx.wear.tiles.material.layouts {
 
+  public class EdgeContentLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
+    method public static androidx.wear.tiles.material.layouts.EdgeContentLayout? fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getContent();
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getEdgeContent();
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getPrimaryLabelTextContent();
+    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getSecondaryLabelTextContent();
+  }
+
+  public static final class EdgeContentLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
+    ctor public EdgeContentLayout.Builder(androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout build();
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setEdgeContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setPrimaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+    method public androidx.wear.tiles.material.layouts.EdgeContentLayout.Builder setSecondaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
+  }
+
   public class LayoutDefaults {
     field public static final androidx.wear.tiles.DimensionBuilders.DpProp DEFAULT_VERTICAL_SPACER_HEIGHT;
+    field public static final float EDGE_CONTENT_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP = 6.0f;
+    field public static final float EDGE_CONTENT_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP = 8.0f;
     field public static final int MULTI_BUTTON_MAX_NUMBER = 7; // 0x7
     field public static final androidx.wear.tiles.DimensionBuilders.DpProp MULTI_SLOT_LAYOUT_HORIZONTAL_SPACER_WIDTH;
-    field public static final float PROGRESS_INDICATOR_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP = 6.0f;
-    field public static final float PROGRESS_INDICATOR_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP = 8.0f;
   }
 
   public class MultiButtonLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
@@ -278,22 +294,5 @@
     method public androidx.wear.tiles.material.layouts.PrimaryLayout.Builder setVerticalSpacerHeight(@Dimension(unit=androidx.annotation.Dimension.DP) float);
   }
 
-  public class ProgressIndicatorLayout implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement {
-    method public static androidx.wear.tiles.material.layouts.ProgressIndicatorLayout? fromLayoutElement(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getPrimaryLabelTextContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getProgressIndicatorContent();
-    method public androidx.wear.tiles.LayoutElementBuilders.LayoutElement? getSecondaryLabelTextContent();
-  }
-
-  public static final class ProgressIndicatorLayout.Builder implements androidx.wear.tiles.LayoutElementBuilders.LayoutElement.Builder {
-    ctor public ProgressIndicatorLayout.Builder(androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout build();
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setPrimaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setProgressIndicatorContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-    method public androidx.wear.tiles.material.layouts.ProgressIndicatorLayout.Builder setSecondaryLabelTextContent(androidx.wear.tiles.LayoutElementBuilders.LayoutElement);
-  }
-
 }
 
diff --git a/wear/tiles/tiles-material/lint-baseline.xml b/wear/tiles/tiles-material/lint-baseline.xml
deleted file mode 100644
index 6040670..0000000
--- a/wear/tiles/tiles-material/lint-baseline.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="ResourceType"
-        message="Mismatched @Dimension units here; expected a pixel integer but received density-independent (dp) integer"
-        errorLine1="            mSize = dp(size);"
-        errorLine2="                       ~~~~">
-        <location
-            file="src/main/java/androidx/wear/tiles/material/Button.java"/>
-    </issue>
-
-    <issue
-        id="ResourceType"
-        message="Mismatched @Dimension units here; expected density-independent (dp) integer but received a pixel integer"
-        errorLine1="        return recommendedIconSize(buttonSize.getValue());"
-        errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/wear/tiles/material/ButtonDefaults.java"/>
-    </issue>
-
-    <issue
-        id="ResourceType"
-        message="Mismatched @Dimension units here; expected a pixel integer but received density-independent (dp) integer"
-        errorLine1="            mWidth = dp(width);"
-        errorLine2="                        ~~~~~">
-        <location
-            file="src/main/java/androidx/wear/tiles/material/Chip.java"/>
-    </issue>
-
-    <issue
-        id="ResourceType"
-        message="Mismatched @Dimension units here; expected a pixel integer but received density-independent (dp) integer"
-        errorLine1="            this.mStrokeWidth = dp(strokeWidth);"
-        errorLine2="                                   ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/wear/tiles/material/CircularProgressIndicator.java"/>
-    </issue>
-
-    <issue
-        id="ResourceType"
-        message="Mismatched @Dimension units here; expected a pixel integer but received density-independent (dp) integer"
-        errorLine1="            this.mHorizontalSpacerWidth = dp(width);"
-        errorLine2="                                             ~~~~~">
-        <location
-            file="src/main/java/androidx/wear/tiles/material/layouts/MultiSlotLayout.java"/>
-    </issue>
-
-    <issue
-        id="ResourceType"
-        message="Mismatched @Dimension units here; expected a pixel integer but received density-independent (dp) integer"
-        errorLine1="            this.mVerticalSpacerHeight = dp(height);"
-        errorLine2="                                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/wear/tiles/material/layouts/MultiSlotLayout.java"/>
-    </issue>
-
-    <issue
-        id="ResourceType"
-        message="Mismatched @Dimension units here; expected a pixel integer but received density-independent (dp) integer"
-        errorLine1="            mWidth = dp(width);"
-        errorLine2="                        ~~~~~">
-        <location
-            file="src/main/java/androidx/wear/tiles/material/TitleChip.java"/>
-    </issue>
-
-</issues>
diff --git a/wear/tiles/tiles-material/src/androidTest/AndroidManifest.xml b/wear/tiles/tiles-material/src/androidTest/AndroidManifest.xml
index 55cb77e..2ebf2db 100644
--- a/wear/tiles/tiles-material/src/androidTest/AndroidManifest.xml
+++ b/wear/tiles/tiles-material/src/androidTest/AndroidManifest.xml
@@ -14,8 +14,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="androidx.wear.tiles.material">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
     <application
         android:label="Golden Tests"
         android:supportsRtl="true"
diff --git a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/TestCasesGenerator.java b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/TestCasesGenerator.java
index a848e90..3b62f26 100644
--- a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/TestCasesGenerator.java
+++ b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/TestCasesGenerator.java
@@ -73,22 +73,22 @@
         testCases.put(
                 "extralarge_secondary_icon_after_button_golden" + NORMAL_SCALE_SUFFIX,
                 new Button.Builder(context, clickable)
-                        .setButtonColors(ButtonDefaults.SECONDARY_BUTTON_COLORS)
+                        .setButtonColors(ButtonDefaults.SECONDARY_COLORS)
                         .setIconContent(ICON_ID)
-                        .setSize(ButtonDefaults.EXTRA_LARGE_BUTTON_SIZE)
+                        .setSize(ButtonDefaults.EXTRA_LARGE_SIZE)
                         .build());
         testCases.put(
                 "large_secondary_icon_40size_button_golden" + NORMAL_SCALE_SUFFIX,
                 new Button.Builder(context, clickable)
-                        .setSize(ButtonDefaults.LARGE_BUTTON_SIZE)
-                        .setButtonColors(ButtonDefaults.SECONDARY_BUTTON_COLORS)
+                        .setSize(ButtonDefaults.LARGE_SIZE)
+                        .setButtonColors(ButtonDefaults.SECONDARY_COLORS)
                         .setIconContent(ICON_ID, dp(40))
                         .build());
         testCases.put(
                 "extralarge_custom_text_custom_sizefont_button_golden" + goldenSuffix,
                 new Button.Builder(context, clickable)
                         .setButtonColors(new ButtonColors(Color.YELLOW, Color.GREEN))
-                        .setSize(ButtonDefaults.EXTRA_LARGE_BUTTON_SIZE)
+                        .setSize(ButtonDefaults.EXTRA_LARGE_SIZE)
                         .setCustomContent(
                                 new Text.Builder(context, "ABC")
                                         .setTypography(Typography.TYPOGRAPHY_DISPLAY1)
@@ -106,32 +106,35 @@
         testCases.put(
                 "default_chip_maintext_golden" + goldenSuffix,
                 new Chip.Builder(context, clickable, deviceParameters)
-                        .setPrimaryTextContent(mainText)
-                        .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
+                        .setPrimaryLabelContent(mainText)
                         .build());
         testCases.put(
                 "default_chip_maintextlabeltext_golden" + goldenSuffix,
                 new Chip.Builder(context, clickable, deviceParameters)
-                        .setPrimaryTextLabelContent(mainText, labelText)
+                        .setPrimaryLabelContent(mainText)
+                        .setSecondaryLabelContent(labelText)
                         .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
                         .build());
         testCases.put(
                 "default_chip_maintexticon_golden" + goldenSuffix,
                 new Chip.Builder(context, clickable, deviceParameters)
-                        .setPrimaryTextIconContent(mainText, ICON_ID)
+                        .setPrimaryLabelContent(mainText)
+                        .setIconContent(ICON_ID)
                         .build());
         testCases.put(
                 "secondary_chip_maintext_centered_golden" + goldenSuffix,
                 new Chip.Builder(context, clickable, deviceParameters)
                         .setHorizontalAlignment(HORIZONTAL_ALIGN_CENTER)
                         .setChipColors(ChipDefaults.SECONDARY_COLORS)
-                        .setPrimaryTextContent(mainText)
+                        .setPrimaryLabelContent(mainText)
                         .build());
         testCases.put(
                 "custom_chip_all_overflows_golden" + goldenSuffix,
                 new Chip.Builder(context, clickable, deviceParameters)
                         .setWidth(130)
-                        .setPrimaryTextLabelIconContent(mainText, labelText, ICON_ID)
+                        .setPrimaryLabelContent(mainText)
+                        .setSecondaryLabelContent(labelText)
+                        .setIconContent(ICON_ID)
                         .setChipColors(
                                 new ChipColors(Color.YELLOW, Color.GREEN, Color.BLACK, Color.GRAY))
                         .build());
@@ -139,18 +142,23 @@
                 "default_chip_all_centered_golden" + goldenSuffix,
                 new Chip.Builder(context, clickable, deviceParameters)
                         .setHorizontalAlignment(HORIZONTAL_ALIGN_CENTER)
-                        .setPrimaryTextLabelIconContent(mainText, labelText, ICON_ID)
+                        .setPrimaryLabelContent(mainText)
+                        .setSecondaryLabelContent(labelText)
+                        .setIconContent(ICON_ID)
                         .build());
         testCases.put(
                 "default_chip_all_rigthalign_golden" + goldenSuffix,
                 new Chip.Builder(context, clickable, deviceParameters)
                         .setHorizontalAlignment(HORIZONTAL_ALIGN_END)
-                        .setPrimaryTextLabelIconContent(mainText, labelText, ICON_ID)
+                        .setPrimaryLabelContent(mainText)
+                        .setSecondaryLabelContent(labelText)
+                        .setIconContent(ICON_ID)
                         .build());
         testCases.put(
                 "custom_chip_icon_primary_overflows_golden" + goldenSuffix,
                 new Chip.Builder(context, clickable, deviceParameters)
-                        .setPrimaryTextIconContent(mainText, ICON_ID)
+                        .setPrimaryLabelContent(mainText)
+                        .setIconContent(ICON_ID)
                         .setWidth(150)
                         .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
                         .setChipColors(
@@ -193,7 +201,7 @@
         testCases.put(
                 "chip_2lines_primary_overflows_golden" + goldenSuffix,
                 new Chip.Builder(context, clickable, deviceParameters)
-                        .setPrimaryTextContent("abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde")
+                        .setPrimaryLabelContent("abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde")
                         .build());
 
         // Different text lengths to test expanding the width based on the size of text. If it's
diff --git a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/layouts/TestCasesGenerator.java b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/layouts/TestCasesGenerator.java
index 94388b4..9738382 100644
--- a/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/layouts/TestCasesGenerator.java
+++ b/wear/tiles/tiles-material/src/androidTest/java/androidx/wear/tiles/material/layouts/TestCasesGenerator.java
@@ -299,8 +299,8 @@
                         .build();
         testCases.put(
                 "default_text_progressindicatorlayout_golden" + goldenSuffix,
-                new ProgressIndicatorLayout.Builder(deviceParameters)
-                        .setProgressIndicatorContent(progressIndicatorBuilder.build())
+                new EdgeContentLayout.Builder(deviceParameters)
+                        .setEdgeContent(progressIndicatorBuilder.build())
                         .setPrimaryLabelTextContent(
                                 new Text.Builder(context, "Primary label")
                                         .setTypography(Typography.TYPOGRAPHY_CAPTION1)
@@ -315,14 +315,14 @@
                         .build());
         testCases.put(
                 "default_empty_progressindicatorlayout_golden" + NORMAL_SCALE_SUFFIX,
-                new ProgressIndicatorLayout.Builder(deviceParameters)
-                        .setProgressIndicatorContent(progressIndicatorBuilder.build())
+                new EdgeContentLayout.Builder(deviceParameters)
+                        .setEdgeContent(progressIndicatorBuilder.build())
                         .build());
         testCases.put(
                 "custom_progressindicatorlayout_golden" + goldenSuffix,
-                new ProgressIndicatorLayout.Builder(deviceParameters)
+                new EdgeContentLayout.Builder(deviceParameters)
                         .setContent(textContent)
-                        .setProgressIndicatorContent(
+                        .setEdgeContent(
                                 progressIndicatorBuilder
                                         .setCircularProgressIndicatorColors(
                                                 new ProgressIndicatorColors(
@@ -331,8 +331,8 @@
                         .build());
         testCases.put(
                 "coloredbox_progressindicatorlayout_golden" + NORMAL_SCALE_SUFFIX,
-                new ProgressIndicatorLayout.Builder(deviceParameters)
-                        .setProgressIndicatorContent(
+                new EdgeContentLayout.Builder(deviceParameters)
+                        .setEdgeContent(
                                 progressIndicatorBuilder
                                         .setCircularProgressIndicatorColors(
                                                 ProgressIndicatorDefaults.DEFAULT_COLORS)
@@ -362,17 +362,17 @@
         Button largeButton1 =
                 new Button.Builder(context, clickable)
                         .setTextContent("1")
-                        .setSize(ButtonDefaults.LARGE_BUTTON_SIZE)
+                        .setSize(ButtonDefaults.LARGE_SIZE)
                         .build();
         Button largeButton2 =
                 new Button.Builder(context, clickable)
                         .setTextContent("2")
-                        .setSize(ButtonDefaults.LARGE_BUTTON_SIZE)
+                        .setSize(ButtonDefaults.LARGE_SIZE)
                         .build();
         Button extraLargeButton =
                 new Button.Builder(context, clickable)
                         .setTextContent("1")
-                        .setSize(ButtonDefaults.EXTRA_LARGE_BUTTON_SIZE)
+                        .setSize(ButtonDefaults.EXTRA_LARGE_SIZE)
                         .build();
         testCases.put(
                 "multibutton_layout_1button_golden" + goldenSuffix,
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 3d4e167..14cc781 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
@@ -19,10 +19,10 @@
 import static androidx.annotation.Dimension.DP;
 import static androidx.wear.tiles.DimensionBuilders.dp;
 import static androidx.wear.tiles.LayoutElementBuilders.CONTENT_SCALE_MODE_FILL_BOUNDS;
-import static androidx.wear.tiles.material.ButtonDefaults.DEFAULT_BUTTON_SIZE;
-import static androidx.wear.tiles.material.ButtonDefaults.EXTRA_LARGE_BUTTON_SIZE;
-import static androidx.wear.tiles.material.ButtonDefaults.LARGE_BUTTON_SIZE;
-import static androidx.wear.tiles.material.ButtonDefaults.PRIMARY_BUTTON_COLORS;
+import static androidx.wear.tiles.material.ButtonDefaults.DEFAULT_SIZE;
+import static androidx.wear.tiles.material.ButtonDefaults.EXTRA_LARGE_SIZE;
+import static androidx.wear.tiles.material.ButtonDefaults.LARGE_SIZE;
+import static androidx.wear.tiles.material.ButtonDefaults.PRIMARY_COLORS;
 import static androidx.wear.tiles.material.Helper.checkNotNull;
 import static androidx.wear.tiles.material.Helper.checkTag;
 import static androidx.wear.tiles.material.Helper.getMetadataTagName;
@@ -65,8 +65,8 @@
  * <p>The Button is circular in shape. The recommended sizes are defined in {@link ButtonDefaults}.
  *
  * <p>The recommended set of {@link ButtonColors} styles can be obtained from {@link
- * ButtonDefaults}., e.g. {@link ButtonDefaults#PRIMARY_BUTTON_COLORS} to get a color scheme for a
- * primary {@link Button}.
+ * ButtonDefaults}., e.g. {@link ButtonDefaults#PRIMARY_COLORS} to get a color scheme for a primary
+ * {@link Button}.
  *
  * <p>When accessing the contents of a container for testing, note that this element can't be simply
  * casted back to the original type, i.e.:
@@ -126,13 +126,13 @@
         @Nullable private LayoutElement mCustomContent;
         @NonNull private final Clickable mClickable;
         @NonNull private CharSequence mContentDescription = "";
-        @NonNull private DpProp mSize = DEFAULT_BUTTON_SIZE;
+        @NonNull private DpProp mSize = DEFAULT_SIZE;
         @Nullable private String mText = null;
         @Nullable private Integer mTypographyName = null;
         @Nullable private String mIcon = null;
         @Nullable private DpProp mIconSize = null;
         @Nullable private String mImage = null;
-        @NonNull private ButtonColors mButtonColors = PRIMARY_BUTTON_COLORS;
+        @NonNull private ButtonColors mButtonColors = PRIMARY_COLORS;
         @ButtonType private int mType = NOT_SET;
 
         static {
@@ -168,9 +168,9 @@
 
         /**
          * Sets the size for the {@link Button}. Strongly recommended values are {@link
-         * ButtonDefaults#DEFAULT_BUTTON_SIZE}, {@link ButtonDefaults#LARGE_BUTTON_SIZE} and {@link
-         * ButtonDefaults#EXTRA_LARGE_BUTTON_SIZE}. If not set, {@link
-         * ButtonDefaults#DEFAULT_BUTTON_SIZE} will be used.
+         * ButtonDefaults#DEFAULT_SIZE}, {@link ButtonDefaults#LARGE_SIZE} and {@link
+         * ButtonDefaults#EXTRA_LARGE_SIZE}. If not set, {@link
+         * ButtonDefaults#DEFAULT_SIZE} will be used.
          */
         @NonNull
         public Builder setSize(@NonNull DpProp size) {
@@ -180,9 +180,9 @@
 
         /**
          * Sets the size for the {@link Button}. Strongly recommended values are {@link
-         * ButtonDefaults#DEFAULT_BUTTON_SIZE}, {@link ButtonDefaults#LARGE_BUTTON_SIZE} and {@link
-         * ButtonDefaults#EXTRA_LARGE_BUTTON_SIZE}. If not set, {@link
-         * ButtonDefaults#DEFAULT_BUTTON_SIZE} will be used.
+         * ButtonDefaults#DEFAULT_SIZE}, {@link ButtonDefaults#LARGE_SIZE} and {@link
+         * ButtonDefaults#EXTRA_LARGE_SIZE}. If not set, {@link
+         * ButtonDefaults#DEFAULT_SIZE} will be used.
          */
         @NonNull
         public Builder setSize(@Dimension(unit = DP) float size) {
@@ -191,9 +191,8 @@
         }
 
         /**
-         * Sets the colors for the {@link Button}. If set, {@link ButtonColors#getBackgroundColor()}
-         * will be used for the background of the button. If not set, {@link
-         * ButtonDefaults#PRIMARY_BUTTON_COLORS} will be used.
+         * Sets the colors for the {@link Button}. If not set, {@link ButtonDefaults#PRIMARY_COLORS}
+         * will be used.
          */
         @NonNull
         public Builder setButtonColors(@NonNull ButtonColors buttonColors) {
@@ -213,15 +212,15 @@
         }
 
         /**
-         * Sets the content of this Button to be the given icon. Any previously added content will
-         * be overridden. Provided icon will be tinted to the given content color from {@link
-         * ButtonColors} and with the given size. This icon should be image with chosen alpha
-         * channel and not an actual image.
+         * Sets the content of this Button to be the given icon with the given size. Any previously
+         * added content will be overridden. Provided icon will be tinted to the given content color
+         * from {@link ButtonColors} and with the given size. This icon should be image with chosen
+         * alpha channel and not an actual image.
          */
         @NonNull
-        public Builder setIconContent(@NonNull String resourceId, @NonNull DpProp size) {
+        public Builder setIconContent(@NonNull String imageResourceId, @NonNull DpProp size) {
             resetContent();
-            this.mIcon = resourceId;
+            this.mIcon = imageResourceId;
             this.mType = ICON;
             this.mIconSize = size;
             return this;
@@ -234,17 +233,17 @@
          * should be image with chosen alpha channel and not an actual image.
          */
         @NonNull
-        public Builder setIconContent(@NonNull String resourceId) {
+        public Builder setIconContent(@NonNull String imageResourceId) {
             resetContent();
-            this.mIcon = resourceId;
+            this.mIcon = imageResourceId;
             this.mType = ICON;
             return this;
         }
 
         /**
          * Sets the content of this Button to be the given text with the default font for the set
-         * size (for the {@link ButtonDefaults#DEFAULT_BUTTON_SIZE}, {@link
-         * ButtonDefaults#LARGE_BUTTON_SIZE} and {@link ButtonDefaults#EXTRA_LARGE_BUTTON_SIZE} is
+         * size (for the {@link ButtonDefaults#DEFAULT_SIZE}, {@link
+         * ButtonDefaults#LARGE_SIZE} and {@link ButtonDefaults#EXTRA_LARGE_SIZE} is
          * {@link Typography#TYPOGRAPHY_TITLE2}, {@link Typography#TYPOGRAPHY_TITLE1} and {@link
          * Typography#TYPOGRAPHY_DISPLAY3} respectively). Any previously added content will be
          * overridden. Text should contain no more than 3 characters, otherwise it will overflow
@@ -274,15 +273,13 @@
         }
 
         /**
-         * Sets the content of this Button to be the given icon with the default size that is half
-         * of the size of the button. Any previously added content will be overridden. Provided icon
-         * will be tinted to the given content color from {@link ButtonColors}. This icon should be
-         * image with chosen alpha channel and not an actual image.
+         * Sets the content of this Button to be the given image, i.e. contacts photo. Any
+         * previously added content will be overridden.
          */
         @NonNull
-        public Builder setImageContent(@NonNull String resourceId) {
+        public Builder setImageContent(@NonNull String imageResourceId) {
             resetContent();
-            this.mImage = resourceId;
+            this.mImage = imageResourceId;
             this.mType = IMAGE;
             return this;
         }
@@ -300,8 +297,6 @@
         @NonNull
         @Override
         public Button build() {
-            assertContentFields();
-
             Modifiers.Builder modifiers =
                     new Modifiers.Builder()
                             .setClickable(mClickable)
@@ -395,38 +390,13 @@
             }
         }
 
-        private void assertContentFields() {
-            int numOfNonNull = 0;
-            if (mText != null) {
-                numOfNonNull++;
-            }
-            if (mIcon != null) {
-                numOfNonNull++;
-            }
-            if (mImage != null) {
-                numOfNonNull++;
-            }
-            if (mCustomContent != null) {
-                numOfNonNull++;
-            }
-            if (numOfNonNull == 0 || mType == NOT_SET) {
-                throw new IllegalArgumentException("Content is not set.");
-            }
-            if (numOfNonNull > 1) {
-                throw new IllegalArgumentException(
-                        "Too many contents are set. Only one content should be set in the button.");
-            }
-        }
-
-        private @TypographyName int getDefaultTypographyForSize(@NonNull DpProp size) {
-            if (size.getValue() == LARGE_BUTTON_SIZE.getValue()) {
+        private static @TypographyName int getDefaultTypographyForSize(@NonNull DpProp size) {
+            if (size.getValue() == LARGE_SIZE.getValue()) {
                 return Typography.TYPOGRAPHY_TITLE1;
+            } else if (size.getValue() == EXTRA_LARGE_SIZE.getValue()) {
+                return Typography.TYPOGRAPHY_DISPLAY3;
             } else {
-                if (size.getValue() == EXTRA_LARGE_BUTTON_SIZE.getValue()) {
-                    return Typography.TYPOGRAPHY_DISPLAY3;
-                } else {
-                    return Typography.TYPOGRAPHY_TITLE2;
-                }
+                return Typography.TYPOGRAPHY_TITLE2;
             }
         }
     }
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ButtonColors.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ButtonColors.java
index 5664ec6..cee5fbd 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ButtonColors.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ButtonColors.java
@@ -25,9 +25,9 @@
 /**
  * Represents the background and content colors used in a button Tiles component.
  *
- * <p>See {@link ButtonDefaults#PRIMARY_BUTTON_COLORS} for the default colors used in a primary
- * styled {@link Button}. See {@link ButtonDefaults#SECONDARY_BUTTON_COLORS} for the default colors
- * used in a secondary styled {@link Button}.
+ * <p>See {@link ButtonDefaults#PRIMARY_COLORS} for the default colors used in a primary styled
+ * {@link Button}. See {@link ButtonDefaults#SECONDARY_COLORS} for the default colors used in a
+ * secondary styled {@link Button}.
  */
 public class ButtonColors {
     @NonNull private final ColorProp mBackgroundColor;
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ButtonDefaults.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ButtonDefaults.java
index 22c21ce..3439061 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ButtonDefaults.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/ButtonDefaults.java
@@ -28,13 +28,13 @@
     private ButtonDefaults() {}
 
     /** The default size for standard {@link Button}. */
-    @NonNull public static final DpProp DEFAULT_BUTTON_SIZE = dp(52);
+    @NonNull public static final DpProp DEFAULT_SIZE = dp(52);
 
     /** The recommended size for large {@link Button}. */
-    @NonNull public static final DpProp LARGE_BUTTON_SIZE = dp(60);
+    @NonNull public static final DpProp LARGE_SIZE = dp(60);
 
     /** The recommended size for extra large {@link Button}. */
-    @NonNull public static final DpProp EXTRA_LARGE_BUTTON_SIZE = dp(88);
+    @NonNull public static final DpProp EXTRA_LARGE_SIZE = dp(88);
 
     /** Returns the recommended icon size for the given size of a {@link Button}. */
     @NonNull
@@ -50,11 +50,11 @@
 
     /** The recommended colors for a primary {@link Button}. */
     @NonNull
-    public static final ButtonColors PRIMARY_BUTTON_COLORS =
+    public static final ButtonColors PRIMARY_COLORS =
             ButtonColors.primaryButtonColors(Colors.DEFAULT);
 
     /** The recommended colors for a secondary {@link Button}. */
     @NonNull
-    public static final ButtonColors SECONDARY_BUTTON_COLORS =
+    public static final ButtonColors SECONDARY_COLORS =
             ButtonColors.secondaryButtonColors(Colors.DEFAULT);
 }
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 7b5a66a..db84840 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
@@ -18,7 +18,9 @@
 
 import static androidx.annotation.Dimension.DP;
 import static androidx.wear.tiles.DimensionBuilders.dp;
+import static androidx.wear.tiles.LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER;
 import static androidx.wear.tiles.LayoutElementBuilders.HORIZONTAL_ALIGN_START;
+import static androidx.wear.tiles.LayoutElementBuilders.HORIZONTAL_ALIGN_UNDEFINED;
 import static androidx.wear.tiles.material.ChipDefaults.DEFAULT_HEIGHT;
 import static androidx.wear.tiles.material.ChipDefaults.DEFAULT_MARGIN_PERCENT;
 import static androidx.wear.tiles.material.ChipDefaults.HORIZONTAL_PADDING;
@@ -52,7 +54,6 @@
 import androidx.wear.tiles.LayoutElementBuilders.LayoutElement;
 import androidx.wear.tiles.LayoutElementBuilders.Row;
 import androidx.wear.tiles.LayoutElementBuilders.Spacer;
-import androidx.wear.tiles.ModifiersBuilders;
 import androidx.wear.tiles.ModifiersBuilders.Background;
 import androidx.wear.tiles.ModifiersBuilders.Clickable;
 import androidx.wear.tiles.ModifiersBuilders.Corner;
@@ -132,17 +133,16 @@
 
         @NonNull private final Context mContext;
         @Nullable private LayoutElement mCustomContent;
-        @NonNull private String mResourceId = "";
-        @NonNull private String mPrimaryText = "";
-        @Nullable private String mLabelText = null;
+        @Nullable private String mImageResourceId = null;
+        @Nullable private String mPrimaryLabel = null;
+        @Nullable private String mSecondaryLabel = null;
         @NonNull private final Clickable mClickable;
         @NonNull private CharSequence mContentDescription = "";
         @NonNull private ContainerDimension mWidth;
         @NonNull private DpProp mHeight = DEFAULT_HEIGHT;
         @NonNull private ChipColors mChipColors = PRIMARY_COLORS;
-        @ChipType private int mType = NOT_SET;
-        @HorizontalAlignment private int mHorizontalAlign = HORIZONTAL_ALIGN_START;
-        @TypographyName private int mPrimaryTextTypography;
+        @HorizontalAlignment private int mHorizontalAlign = HORIZONTAL_ALIGN_UNDEFINED;
+        @TypographyName private int mPrimaryLabelTypography;
         @NonNull private DpProp mHorizontalPadding = HORIZONTAL_PADDING;
         private boolean mIsScalable = true;
         private int mMaxLines = 0; // 0 indicates that is not set.
@@ -176,7 +176,7 @@
                             (100 - 2 * DEFAULT_MARGIN_PERCENT)
                                     * deviceParameters.getScreenWidthDp()
                                     / 100);
-            mPrimaryTextTypography = Typography.TYPOGRAPHY_BUTTON;
+            mPrimaryLabelTypography = Typography.TYPOGRAPHY_BUTTON;
         }
 
         /**
@@ -205,7 +205,9 @@
         @NonNull
         public Builder setCustomContent(@NonNull LayoutElement content) {
             this.mCustomContent = content;
-            this.mType = CUSTOM_CONTENT;
+            this.mPrimaryLabel = "";
+            this.mSecondaryLabel = "";
+            this.mImageResourceId = "";
             return this;
         }
 
@@ -220,90 +222,61 @@
         }
 
         /**
-         * Sets the content of the {@link Chip} to be the given primary text. Any previously added
-         * content will be overridden. Primary text can be on 1 or 2 lines, depending on the length.
+         * Sets the primary label for the {@link Chip}. Any previously added custom content will be
+         * overridden. Primary label can be on 1 or 2 lines, depending on the length and existence
+         * of secondary label.
          */
-        // There's a getter for primary text - getPrimaryText.
         @NonNull
-        @SuppressWarnings("MissingGetterMatchingBuilder")
-        public Builder setPrimaryTextContent(@NonNull String primaryText) {
-            this.mPrimaryText = primaryText;
-            this.mLabelText = null;
-            this.mType = TEXT;
+        public Builder setPrimaryLabelContent(@NonNull String primaryLabel) {
+            this.mPrimaryLabel = primaryLabel;
+            this.mCustomContent = null;
             return this;
         }
 
         /**
          * Used for creating CompactChip and TitleChip.
          *
-         * <p>Sets the font for the primary text and should only be used internally.
+         * <p>Sets the font for the primary label and should only be used internally.
          */
         @NonNull
-        Builder setPrimaryTextTypography(@TypographyName int typography) {
-            this.mPrimaryTextTypography = typography;
+        Builder setPrimaryLabelTypography(@TypographyName int typography) {
+            this.mPrimaryLabelTypography = typography;
             return this;
         }
 
         /**
          * Used for creating CompactChip and TitleChip.
          *
-         * <p>Sets whether the font for the primary text is scalable.
+         * <p>Sets whether the font for the primary label is scalable.
          */
         @NonNull
-        Builder setIsPrimaryTextScalable(boolean isScalable) {
+        Builder setIsPrimaryLabelScalable(boolean isScalable) {
             this.mIsScalable = isScalable;
             return this;
         }
 
         /**
-         * Sets the content of the {@link Chip} to be the given primary text and secondary label.
-         * Any previously added content will be overridden. Primary text can be shown on 1 line
-         * only.
+         * Sets the secondary label for the {@link Chip}. Any previously added custom content will
+         * be overridden. If secondary label is set, primary label must be set too with {@link
+         * #setPrimaryLabelContent}.
          */
-        // There are separate getters for primary text and label.
         @NonNull
-        @SuppressWarnings("MissingGetterMatchingBuilder")
-        public Builder setPrimaryTextLabelContent(
-                @NonNull String primaryText, @NonNull String label) {
-            this.mPrimaryText = primaryText;
-            this.mLabelText = label;
-            this.mType = TEXT;
+        public Builder setSecondaryLabelContent(@NonNull String secondaryLabel) {
+            this.mSecondaryLabel = secondaryLabel;
+            this.mCustomContent = null;
             return this;
         }
 
         /**
-         * Sets the content of the {@link Chip} to be the given primary text with an icon and
-         * secondary label. Any previously added content will be overridden. Provided icon will be
-         * tinted to the given content color from {@link ChipColors}. This icon should be image with
-         * chosen alpha channel and not an actual image.
+         * Sets the icon for the {@link Chip}. Any previously added custom content will be
+         * overridden. Provided icon will be tinted to the given content color from {@link
+         * ChipColors}. This icon should be image with chosen alpha channel and not an actual image.
+         * If icon is set, primary label must be set too with {@link #setPrimaryLabelContent}.
          */
-        // There are separate getters for primary text and icon.
         @NonNull
-        @SuppressWarnings("MissingGetterMatchingBuilder")
-        public Builder setPrimaryTextIconContent(
-                @NonNull String primaryText, @NonNull String resourceId) {
-            this.mPrimaryText = primaryText;
-            this.mResourceId = resourceId;
-            this.mLabelText = null;
-            this.mType = ICON;
-            return this;
-        }
-
-        /**
-         * Sets the content of the {@link Chip} to be the given primary text with an icon. Any
-         * previously added content will be overridden. Provided icon will be tinted to the given
-         * content color from {@link ChipColors}. This icon should be image with chosen alpha
-         * channel and not an actual image. Primary text can be shown on 1 line only.
-         */
-        // There are separate getters for primary text, icon and label.
-        @NonNull
-        @SuppressWarnings("MissingGetterMatchingBuilder")
-        public Builder setPrimaryTextLabelIconContent(
-                @NonNull String primaryText, @NonNull String label, @NonNull String resourceId) {
-            this.mPrimaryText = primaryText;
-            this.mLabelText = label;
-            this.mResourceId = resourceId;
-            this.mType = ICON;
+        public Builder setIconContent(@NonNull String imageResourceId) {
+            this.mImageResourceId = imageResourceId;
+            this.mCustomContent = null;
             return this;
         }
 
@@ -322,8 +295,9 @@
 
         /**
          * Sets the horizontal alignment in the chip. It is strongly recommended that the content of
-         * the chip is start-aligned if there is more than primary text in it. If not set, {@link
-         * HorizontalAlignment#HORIZONTAL_ALIGN_START} will be used.
+         * the chip is start-aligned if there is more than primary text in it. By default, {@link
+         * HorizontalAlignment#HORIZONTAL_ALIGN_CENTER} will be used when only a primary label is
+         * present. Otherwise {@link HorizontalAlignment#HORIZONTAL_ALIGN_START} will be used.
          */
         @NonNull
         public Builder setHorizontalAlignment(@HorizontalAlignment int horizontalAlignment) {
@@ -363,8 +337,6 @@
         @NonNull
         @Override
         public Chip build() {
-            assertContentFields();
-
             Modifiers.Builder modifiers =
                     new Modifiers.Builder()
                             .setClickable(mClickable)
@@ -383,47 +355,72 @@
                                             .build())
                             .setMetadata(
                                     new ElementMetadata.Builder()
-                                            .setTagData(getCorrectMetadataTag())
+                                            .setTagData(getTagBytes(getCorrectMetadataTag()))
+                                            .build())
+                            .setSemantics(
+                                    new Semantics.Builder()
+                                            .setContentDescription(getCorrectContentDescription())
                                             .build());
-            if (mContentDescription.length() > 0) {
-                modifiers.setSemantics(
-                        new ModifiersBuilders.Semantics.Builder()
-                                .setContentDescription(mContentDescription.toString())
-                                .build());
-            }
 
             Box.Builder element =
                     new Box.Builder()
                             .setWidth(mWidth)
                             .setHeight(mHeight)
-                            .setHorizontalAlignment(mHorizontalAlign)
+                            .setHorizontalAlignment(getCorrectHorizontalAlignment())
                             .addContent(getCorrectContent())
                             .setModifiers(modifiers.build());
 
             return new Chip(element.build());
         }
 
-        private void assertContentFields() {
-            if (mType == NOT_SET) {
-                throw new IllegalStateException(
-                        "No content set. Use setPrimaryTextContent or similar method to add"
-                            + " content");
+        @NonNull
+        private String getCorrectContentDescription() {
+            if (mContentDescription.length() == 0) {
+                mContentDescription = "";
+                if (mPrimaryLabel != null) {
+                    mContentDescription += mPrimaryLabel;
+                }
+                if (mSecondaryLabel != null) {
+                    mContentDescription += "\n" + mSecondaryLabel;
+                }
+            }
+            return mContentDescription.toString();
+        }
+
+        @HorizontalAlignment
+        private int getCorrectHorizontalAlignment() {
+            if (mHorizontalAlign != HORIZONTAL_ALIGN_UNDEFINED) {
+                return mHorizontalAlign;
+            }
+            if (mPrimaryLabel != null && mSecondaryLabel == null && mImageResourceId == null) {
+                return HORIZONTAL_ALIGN_CENTER;
+            } else {
+                return HORIZONTAL_ALIGN_START;
             }
         }
 
-        private byte[] getCorrectMetadataTag() {
-            return getTagBytes(
-                    mMetadataTag.isEmpty() ? checkNotNull(TYPE_TO_TAG.get(mType)) : mMetadataTag);
+        private String getCorrectMetadataTag() {
+            if (!mMetadataTag.isEmpty()) {
+                return mMetadataTag;
+            }
+            if (mCustomContent != null) {
+                return METADATA_TAG_CUSTOM_CONTENT;
+            }
+            if (mImageResourceId != null) {
+                return METADATA_TAG_ICON;
+            }
+            return METADATA_TAG_TEXT;
         }
 
         @NonNull
         private LayoutElement getCorrectContent() {
-            if (mType == CUSTOM_CONTENT) {
-                return checkNotNull(mCustomContent);
+            if (mCustomContent != null) {
+                return mCustomContent;
             }
+
             Text mainTextElement =
-                    new Text.Builder(mContext, mPrimaryText)
-                            .setTypography(mPrimaryTextTypography)
+                    new Text.Builder(mContext, checkNotNull(mPrimaryLabel))
+                            .setTypography(mPrimaryLabelTypography)
                             .setColor(mChipColors.getContentColor())
                             .setMaxLines(getCorrectMaxLines())
                             .setOverflow(LayoutElementBuilders.TEXT_OVERFLOW_ELLIPSIZE_END)
@@ -437,9 +434,9 @@
                             .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
                             .addContent(putLayoutInBox(mainTextElement).build());
 
-            if (mLabelText != null) {
+            if (mSecondaryLabel != null) {
                 Text labelTextElement =
-                        new Text.Builder(mContext, mLabelText)
+                        new Text.Builder(mContext, mSecondaryLabel)
                                 .setTypography(Typography.TYPOGRAPHY_CAPTION2)
                                 .setColor(mChipColors.getSecondaryContentColor())
                                 .setMaxLines(1)
@@ -450,13 +447,13 @@
             }
 
             Box texts = putLayoutInBox(column.build()).build();
-            if (mType == TEXT) {
+            if (mImageResourceId == null) {
                 return texts;
             } else {
                 return new Row.Builder()
                         .addContent(
                                 new Image.Builder()
-                                        .setResourceId(mResourceId)
+                                        .setResourceId(mImageResourceId)
                                         .setWidth(ICON_SIZE)
                                         .setHeight(ICON_SIZE)
                                         .setColorFilter(
@@ -479,7 +476,7 @@
             if (mMaxLines > 0) {
                 return mMaxLines;
             }
-            return mLabelText != null ? 1 : 2;
+            return mSecondaryLabel != null ? 1 : 2;
         }
 
         private Box.Builder putLayoutInBox(@NonNull LayoutElement element) {
@@ -527,8 +524,8 @@
                 iconTintColor = checkNotNull(checkNotNull(icon.getColorFilter()).getTint());
             }
 
-            contentColor = checkNotNull(getPrimaryTextContentObject()).getColor();
-            Text label = getLabelContentObject();
+            contentColor = checkNotNull(getPrimaryLabelContentObject()).getColor();
+            Text label = getSecondaryLabelContentObject();
             if (label != null) {
                 secondaryContentColor = label.getColor();
             }
@@ -567,17 +564,17 @@
         return null;
     }
 
-    /** Returns primary text from this Chip if it has been added. Otherwise, it returns null. */
+    /** Returns primary label from this Chip if it has been added. Otherwise, it returns null. */
     @Nullable
-    public String getPrimaryTextContent() {
-        Text primaryText = getPrimaryTextContentObject();
-        return primaryText != null ? primaryText.getText() : null;
+    public String getPrimaryLabelContent() {
+        Text primaryLabel = getPrimaryLabelContentObject();
+        return primaryLabel != null ? primaryLabel.getText() : null;
     }
 
-    /** Returns label text from this Chip if it has been added. Otherwise, it returns null. */
+    /** Returns secondary label from this Chip if it has been added. Otherwise, it returns null. */
     @Nullable
-    public String getLabelContent() {
-        Text label = getLabelContentObject();
+    public String getSecondaryLabelContent() {
+        Text label = getSecondaryLabelContentObject();
         return label != null ? label.getText() : null;
     }
 
@@ -589,13 +586,13 @@
     }
 
     @Nullable
-    private Text getPrimaryTextContentObject() {
-        return getPrimaryOrLabelTextContent(0);
+    private Text getPrimaryLabelContentObject() {
+        return getPrimaryOrSecondaryLabelContent(0);
     }
 
     @Nullable
-    private Text getLabelContentObject() {
-        return getPrimaryOrLabelTextContent(1);
+    private Text getSecondaryLabelContentObject() {
+        return getPrimaryOrSecondaryLabelContent(1);
     }
 
     @Nullable
@@ -607,7 +604,7 @@
     }
 
     @Nullable
-    private Text getPrimaryOrLabelTextContent(int index) {
+    private Text getPrimaryOrSecondaryLabelContent(int index) {
         String metadataTag = getMetadataTag();
         if (metadataTag.equals(METADATA_TAG_CUSTOM_CONTENT)) {
             return null;
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 6fdddeff..a7db44e8 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
@@ -130,9 +130,9 @@
                             .setHeight(COMPACT_HEIGHT)
                             .setMaxLines(1)
                             .setHorizontalPadding(COMPACT_HORIZONTAL_PADDING)
-                            .setPrimaryTextContent(mText)
-                            .setPrimaryTextTypography(Typography.TYPOGRAPHY_CAPTION1)
-                            .setIsPrimaryTextScalable(false);
+                            .setPrimaryLabelContent(mText)
+                            .setPrimaryLabelTypography(Typography.TYPOGRAPHY_CAPTION1)
+                            .setIsPrimaryLabelScalable(false);
 
             return new CompactChip(chipBuilder.build());
         }
@@ -153,7 +153,7 @@
     /** Returns text content of this Chip. */
     @NonNull
     public String getText() {
-        return checkNotNull(mElement.getPrimaryTextContent());
+        return checkNotNull(mElement.getPrimaryLabelContent());
     }
 
     /** Returns metadata tag set to this CompactChip, which should be {@link #METADATA_TAG}. */
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 f20bd23..056089b 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
@@ -165,9 +165,9 @@
                             .setHeight(TITLE_HEIGHT)
                             .setMaxLines(1)
                             .setHorizontalPadding(TITLE_HORIZONTAL_PADDING)
-                            .setPrimaryTextContent(mText)
-                            .setPrimaryTextTypography(Typography.TYPOGRAPHY_TITLE2)
-                            .setIsPrimaryTextScalable(false);
+                            .setPrimaryLabelContent(mText)
+                            .setPrimaryLabelTypography(Typography.TYPOGRAPHY_TITLE2)
+                            .setIsPrimaryLabelScalable(false);
 
             if (mWidth != null) {
                 chipBuilder.setWidth(mWidth);
@@ -198,7 +198,7 @@
     /** Returns text content of this Chip. */
     @NonNull
     public String getText() {
-        return checkNotNull(mElement.getPrimaryTextContent());
+        return checkNotNull(mElement.getPrimaryLabelContent());
     }
 
     /** Returns the horizontal alignment of the content in this Chip. */
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/EdgeContentLayout.java
similarity index 76%
rename from wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/ProgressIndicatorLayout.java
rename to wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/EdgeContentLayout.java
index 79bfecca..d5fcbed 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/EdgeContentLayout.java
@@ -24,10 +24,10 @@
 import static androidx.wear.tiles.material.Helper.getTagBytes;
 import static androidx.wear.tiles.material.Helper.isRoundDevice;
 import static androidx.wear.tiles.material.ProgressIndicatorDefaults.DEFAULT_PADDING;
-import static androidx.wear.tiles.material.layouts.LayoutDefaults.PROGRESS_INDICATOR_LAYOUT_MARGIN_HORIZONTAL_ROUND_DP;
-import static androidx.wear.tiles.material.layouts.LayoutDefaults.PROGRESS_INDICATOR_LAYOUT_MARGIN_HORIZONTAL_SQUARE_DP;
-import static androidx.wear.tiles.material.layouts.LayoutDefaults.PROGRESS_INDICATOR_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP;
-import static androidx.wear.tiles.material.layouts.LayoutDefaults.PROGRESS_INDICATOR_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP;
+import static androidx.wear.tiles.material.layouts.LayoutDefaults.EDGE_CONTENT_LAYOUT_MARGIN_HORIZONTAL_ROUND_DP;
+import static androidx.wear.tiles.material.layouts.LayoutDefaults.EDGE_CONTENT_LAYOUT_MARGIN_HORIZONTAL_SQUARE_DP;
+import static androidx.wear.tiles.material.layouts.LayoutDefaults.EDGE_CONTENT_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP;
+import static androidx.wear.tiles.material.layouts.LayoutDefaults.EDGE_CONTENT_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
@@ -53,10 +53,10 @@
 import java.util.List;
 
 /**
- * Tiles layout that represents the suggested layout style for Material Tiles with the progress
- * indicator around the edges of the screen and the given content inside of it and the recommended
- * margin and padding applied. Optional primary or secondary label can be added above and below the
- * main content, respectively.
+ * Tiles layout that represents the suggested layout style for Material Tiles, which has content
+ * around the edge of the screen (e.g. a ProgressIndicator) and the given content inside of it with
+ * the recommended margin and padding applied. Optional primary or secondary label can be added
+ * above and below the main content, respectively.
  *
  * <p>For additional examples and suggested layouts see <a
  * href="/training/wearables/design/tiles-design-system">Tiles Design System</a>.
@@ -65,28 +65,28 @@
  * casted back to the original type, i.e.:
  *
  * <pre>{@code
- * ProgressIndicatorLayout pil = new ProgressIndicatorLayout...
- * Box box = new Box.Builder().addContent(pil).build();
+ * EdgeContentLayout ecl = new EdgeContentLayout...
+ * Box box = new Box.Builder().addContent(ecl).build();
  *
- * ProgressIndicatorLayout myPil = (ProgressIndicatorLayout) box.getContents().get(0);
+ * EdgeContentLayout myEcl = (EdgeContentLayout) box.getContents().get(0);
  * }</pre>
  *
  * will fail.
  *
- * <p>To be able to get {@link ProgressIndicatorLayout} object from any layout element, {@link
+ * <p>To be able to get {@link EdgeContentLayout} object from any layout element, {@link
  * #fromLayoutElement} method should be used, i.e.:
  *
  * <pre>{@code
- * ProgressIndicatorLayout myPil =
- *   ProgressIndicatorLayout.fromLayoutElement(box.getContents().get(0));
+ * EdgeContentLayout myEcl =
+ *   EdgeContentLayout.fromLayoutElement(box.getContents().get(0));
  * }</pre>
  */
-public class ProgressIndicatorLayout implements LayoutElement {
+public class EdgeContentLayout implements LayoutElement {
     /**
      * Prefix tool tag for Metadata in Modifiers, so we know that Box is actually a
-     * ProgressIndicatorLayout.
+     * EdgeContentLayout.
      */
-    static final String METADATA_TAG_PREFIX = "PIL_";
+    static final String METADATA_TAG_PREFIX = "ECL_";
 
     /**
      * Index for byte array that contains bits to check whether the content and indicator are
@@ -95,17 +95,17 @@
     static final int FLAG_INDEX = METADATA_TAG_PREFIX.length();
 
     /**
-     * Base tool tag for Metadata in Modifiers, so we know that Box is actually a
-     * ProgressIndicatorLayout and what optional content is added.
+     * Base tool tag for Metadata in Modifiers, so we know that Box is actually a EdgeContentLayout
+     * and what optional content is added.
      */
     static final byte[] METADATA_TAG_BASE =
             Arrays.copyOf(getTagBytes(METADATA_TAG_PREFIX), FLAG_INDEX + 1);
 
     /**
      * Bit position in a byte on {@link #FLAG_INDEX} index in metadata byte array to check whether
-     * the progress indicator is present or not.
+     * the edge content is present or not.
      */
-    static final int PROGRESS_INDICATOR_PRESENT = 0x1;
+    static final int EDGE_CONTENT_PRESENT = 0x1;
     /**
      * Bit position in a byte on {@link #FLAG_INDEX} index in metadata byte array to check whether
      * the primary label is present or not.
@@ -128,7 +128,7 @@
     @IntDef(
             flag = true,
             value = {
-                PROGRESS_INDICATOR_PRESENT,
+                EDGE_CONTENT_PRESENT,
                 PRIMARY_LABEL_PRESENT,
                 CONTENT_PRESENT,
                 SECONDARY_LABEL_PRESENT
@@ -137,40 +137,42 @@
 
     @NonNull private final Box mImpl;
 
-    // This contains inner columns and progress indicator.
+    // This contains inner columns and edge content.
     @NonNull private final List<LayoutElement> mContents;
 
     // This contains optional labels, spacers and main content.
     @NonNull private final List<LayoutElement> mInnerColumn;
 
-    ProgressIndicatorLayout(@NonNull Box layoutElement) {
+    EdgeContentLayout(@NonNull Box layoutElement) {
         this.mImpl = layoutElement;
         this.mContents = mImpl.getContents();
         this.mInnerColumn = ((Column) ((Box) mContents.get(0)).getContents().get(0)).getContents();
     }
 
-    /** Builder class for {@link ProgressIndicatorLayout}. */
+    /** Builder class for {@link EdgeContentLayout}. */
     public static final class Builder implements LayoutElement.Builder {
         @NonNull private final DeviceParameters mDeviceParameters;
-        @Nullable private LayoutElement mProgressIndicator = null;
+        @Nullable private LayoutElement mEdgeContent = null;
         @Nullable private LayoutElement mPrimaryLabelText = null;
         @Nullable private LayoutElement mSecondaryLabelText = null;
         @Nullable private LayoutElement mContent = null;
         private byte mMetadataContentByte = 0;
 
         /**
-         * Creates a builder for the {@link ProgressIndicatorLayout}t. Custom content inside of it
-         * can later be set with ({@link #setContent}.
+         * Creates a builder for the {@link EdgeContentLayout}t. Custom content inside of it can
+         * later be set with ({@link #setContent}.
          */
         public Builder(@NonNull DeviceParameters deviceParameters) {
             this.mDeviceParameters = deviceParameters;
         }
 
-        /** Sets the progress indicator which will be around the edges. */
+        /**
+         * Sets the content to be around the edges. This can be {@link CircularProgressIndicator}.
+         */
         @NonNull
-        public Builder setProgressIndicatorContent(@NonNull LayoutElement progressIndicator) {
-            this.mProgressIndicator = progressIndicator;
-            mMetadataContentByte = (byte) (mMetadataContentByte | PROGRESS_INDICATOR_PRESENT);
+        public Builder setEdgeContent(@NonNull LayoutElement edgeContent) {
+            this.mEdgeContent = edgeContent;
+            mMetadataContentByte = (byte) (mMetadataContentByte | EDGE_CONTENT_PRESENT);
             return this;
         }
 
@@ -201,23 +203,18 @@
             return this;
         }
 
-        /**
-         * Constructs and returns {@link ProgressIndicatorLayout} with the provided content and
-         * look.
-         */
+        /** Constructs and returns {@link EdgeContentLayout} with the provided content and look. */
         @NonNull
         @Override
-        public ProgressIndicatorLayout build() {
+        public EdgeContentLayout build() {
             float thicknessDp =
-                    mProgressIndicator instanceof CircularProgressIndicator
-                            ? ((CircularProgressIndicator) mProgressIndicator)
-                                    .getStrokeWidth()
-                                    .getValue()
+                    mEdgeContent instanceof CircularProgressIndicator
+                            ? ((CircularProgressIndicator) mEdgeContent).getStrokeWidth().getValue()
                             : 0;
             float horizontalPaddingDp =
                     isRoundDevice(mDeviceParameters)
-                            ? PROGRESS_INDICATOR_LAYOUT_MARGIN_HORIZONTAL_ROUND_DP
-                            : PROGRESS_INDICATOR_LAYOUT_MARGIN_HORIZONTAL_SQUARE_DP;
+                            ? EDGE_CONTENT_LAYOUT_MARGIN_HORIZONTAL_ROUND_DP
+                            : EDGE_CONTENT_LAYOUT_MARGIN_HORIZONTAL_SQUARE_DP;
             float indicatorWidth = 2 * (thicknessDp + DEFAULT_PADDING.getValue());
             float mainContentHeightDp = mDeviceParameters.getScreenHeightDp() - indicatorWidth;
             float mainContentWidthDp = mDeviceParameters.getScreenWidthDp() - indicatorWidth;
@@ -258,8 +255,7 @@
                 innerContentBuilder.addContent(mPrimaryLabelText);
                 innerContentBuilder.addContent(
                         new Spacer.Builder()
-                                .setHeight(
-                                        dp(PROGRESS_INDICATOR_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP))
+                                .setHeight(dp(EDGE_CONTENT_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP))
                                 .build());
             }
 
@@ -274,8 +270,7 @@
             if (mSecondaryLabelText != null) {
                 innerContentBuilder.addContent(
                         new Spacer.Builder()
-                                .setHeight(
-                                        dp(PROGRESS_INDICATOR_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP))
+                                .setHeight(dp(EDGE_CONTENT_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP))
                                 .build());
                 innerContentBuilder.addContent(mSecondaryLabelText);
             }
@@ -290,11 +285,11 @@
                             .addContent(innerContentBuilder.build())
                             .build());
 
-            if (mProgressIndicator != null) {
-                mainBoxBuilder.addContent(mProgressIndicator);
+            if (mEdgeContent != null) {
+                mainBoxBuilder.addContent(mEdgeContent);
             }
 
-            return new ProgressIndicatorLayout(mainBoxBuilder.build());
+            return new EdgeContentLayout(mainBoxBuilder.build());
         }
     }
 
@@ -302,7 +297,7 @@
         return (getMetadataTag()[FLAG_INDEX] & elementFlag) == elementFlag;
     }
 
-    /** Returns metadata tag set to this ProgressIndicatorLayout. */
+    /** Returns metadata tag set to this EdgeContentLayout. */
     @NonNull
     byte[] getMetadataTag() {
         return getMetadataTagBytes(checkNotNull(checkNotNull(mImpl.getModifiers()).getMetadata()));
@@ -340,24 +335,24 @@
         return mInnerColumn.get(mInnerColumn.size() - 1);
     }
 
-    /** Returns the progress indicator content from this layout. */
+    /** Returns the edge content from this layout. */
     @Nullable
-    public LayoutElement getProgressIndicatorContent() {
-        if (areElementsPresent(PROGRESS_INDICATOR_PRESENT)) {
+    public LayoutElement getEdgeContent() {
+        if (areElementsPresent(EDGE_CONTENT_PRESENT)) {
             return mContents.get(1);
         }
         return null;
     }
 
     /**
-     * Returns ProgressIndicatorLayout object from the given LayoutElement (e.g. one retrieved from
-     * a container's content with {@code container.getContents().get(index)}) if that element can be
-     * converted to ProgressIndicatorLayout. Otherwise, it will return null.
+     * Returns EdgeContentLayout object from the given LayoutElement (e.g. one retrieved from a
+     * container's content with {@code container.getContents().get(index)}) if that element can be
+     * converted to EdgeContentLayout. Otherwise, it will return null.
      */
     @Nullable
-    public static ProgressIndicatorLayout fromLayoutElement(@NonNull LayoutElement element) {
-        if (element instanceof ProgressIndicatorLayout) {
-            return (ProgressIndicatorLayout) element;
+    public static EdgeContentLayout fromLayoutElement(@NonNull LayoutElement element) {
+        if (element instanceof EdgeContentLayout) {
+            return (EdgeContentLayout) element;
         }
         if (!(element instanceof Box)) {
             return null;
@@ -366,8 +361,8 @@
         if (!checkTag(boxElement.getModifiers(), METADATA_TAG_PREFIX, METADATA_TAG_BASE)) {
             return null;
         }
-        // Now we are sure that this element is a ProgressIndicatorLayout.
-        return new ProgressIndicatorLayout(boxElement);
+        // Now we are sure that this element is a EdgeContentLayout.
+        return new EdgeContentLayout(boxElement);
     }
 
     /** @hide */
diff --git a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/LayoutDefaults.java b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/LayoutDefaults.java
index 19bc708..c56a119 100644
--- a/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/LayoutDefaults.java
+++ b/wear/tiles/tiles-material/src/main/java/androidx/wear/tiles/material/layouts/LayoutDefaults.java
@@ -74,23 +74,23 @@
     /** The default spacer height for primary chip in the {@link PrimaryLayout}. */
     static final DpProp PRIMARY_LAYOUT_SPACER_HEIGHT = dp(12);
 
-    /** The default horizontal margin in the {@link ProgressIndicatorLayout}. */
-    static final float PROGRESS_INDICATOR_LAYOUT_MARGIN_HORIZONTAL_ROUND_DP = 14;
+    /** The default horizontal margin in the {@link EdgeContentLayout}. */
+    static final float EDGE_CONTENT_LAYOUT_MARGIN_HORIZONTAL_ROUND_DP = 14;
 
-    /** The default horizontal margin in the {@link ProgressIndicatorLayout}. */
-    static final float PROGRESS_INDICATOR_LAYOUT_MARGIN_HORIZONTAL_SQUARE_DP = 16;
+    /** The default horizontal margin in the {@link EdgeContentLayout}. */
+    static final float EDGE_CONTENT_LAYOUT_MARGIN_HORIZONTAL_SQUARE_DP = 16;
 
     /**
      * The recommended padding that should be above the main content (text) in the {@link
-     * ProgressIndicatorLayout}.
+     * EdgeContentLayout}.
      */
-    public static final float PROGRESS_INDICATOR_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP = 6;
+    public static final float EDGE_CONTENT_LAYOUT_PADDING_ABOVE_MAIN_CONTENT_DP = 6;
 
     /**
      * The recommended padding that should be below the main content (text) in the {@link
-     * ProgressIndicatorLayout}.
+     * EdgeContentLayout}.
      */
-    public static final float PROGRESS_INDICATOR_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP = 8;
+    public static final float EDGE_CONTENT_LAYOUT_PADDING_BELOW_MAIN_CONTENT_DP = 8;
 
     /** The default spacer width for slots in a {@link MultiSlotLayout}. */
     public static final DpProp MULTI_SLOT_LAYOUT_HORIZONTAL_SPACER_WIDTH = dp(8);
@@ -105,15 +105,15 @@
      * The default size of button in case when there are 3 or more buttons in the {@link
      * MultiButtonLayout}.
      */
-    static final DpProp MULTI_BUTTON_3_PLUS_SIZE = ButtonDefaults.DEFAULT_BUTTON_SIZE;
+    static final DpProp MULTI_BUTTON_3_PLUS_SIZE = ButtonDefaults.DEFAULT_SIZE;
 
     /** The default size of button in case when there 2 buttons in the {@link MultiButtonLayout}. */
-    static final DpProp MULTI_BUTTON_2_SIZE = ButtonDefaults.LARGE_BUTTON_SIZE;
+    static final DpProp MULTI_BUTTON_2_SIZE = ButtonDefaults.LARGE_SIZE;
 
     /**
      * The default size of button in case when there is 1 button in the {@link MultiButtonLayout}.
      */
-    static final DpProp MULTI_BUTTON_1_SIZE = ButtonDefaults.EXTRA_LARGE_BUTTON_SIZE;
+    static final DpProp MULTI_BUTTON_1_SIZE = ButtonDefaults.EXTRA_LARGE_SIZE;
 
     /** The default width for vertical spacer between buttons in the {@link MultiButtonLayout}. */
     static final DpProp MULTI_BUTTON_SPACER_WIDTH = dp(8);
diff --git a/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/ButtonTest.java b/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/ButtonTest.java
index e48b73a..57facdb 100644
--- a/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/ButtonTest.java
+++ b/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/ButtonTest.java
@@ -18,15 +18,13 @@
 
 import static androidx.wear.tiles.ColorBuilders.argb;
 import static androidx.wear.tiles.DimensionBuilders.dp;
-import static androidx.wear.tiles.material.ButtonDefaults.DEFAULT_BUTTON_SIZE;
-import static androidx.wear.tiles.material.ButtonDefaults.EXTRA_LARGE_BUTTON_SIZE;
-import static androidx.wear.tiles.material.ButtonDefaults.LARGE_BUTTON_SIZE;
-import static androidx.wear.tiles.material.ButtonDefaults.PRIMARY_BUTTON_COLORS;
+import static androidx.wear.tiles.material.ButtonDefaults.DEFAULT_SIZE;
+import static androidx.wear.tiles.material.ButtonDefaults.EXTRA_LARGE_SIZE;
+import static androidx.wear.tiles.material.ButtonDefaults.LARGE_SIZE;
+import static androidx.wear.tiles.material.ButtonDefaults.PRIMARY_COLORS;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assert.assertThrows;
-
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import android.content.Context;
@@ -64,19 +62,12 @@
             new Text.Builder(CONTEXT, "ABC").setColor(argb(0)).build();
 
     @Test
-    public void testButtonEmpty() {
-        assertThrows(
-                IllegalArgumentException.class,
-                () -> new Button.Builder(CONTEXT, CLICKABLE).build());
-    }
-
-    @Test
     public void testButtonCustomAddedContentNoContentDesc() {
         Button button = new Button.Builder(CONTEXT, CLICKABLE).setCustomContent(CONTENT).build();
 
         assertButton(
                 button,
-                DEFAULT_BUTTON_SIZE,
+                DEFAULT_SIZE,
                 new ButtonColors(Colors.PRIMARY, 0),
                 null,
                 Button.METADATA_TAG_CUSTOM_CONTENT,
@@ -88,7 +79,7 @@
 
     @Test
     public void testButtonCustom() {
-        DpProp mSize = LARGE_BUTTON_SIZE;
+        DpProp mSize = LARGE_SIZE;
         ButtonColors mButtonColors = new ButtonColors(0x11223344, 0);
 
         Button button =
@@ -122,8 +113,8 @@
 
         assertButton(
                 button,
-                DEFAULT_BUTTON_SIZE,
-                PRIMARY_BUTTON_COLORS,
+                DEFAULT_SIZE,
+                PRIMARY_COLORS,
                 CONTENT_DESCRIPTION,
                 Button.METADATA_TAG_ICON,
                 null,
@@ -137,14 +128,14 @@
         Button button =
                 new Button.Builder(CONTEXT, CLICKABLE)
                         .setIconContent(RESOURCE_ID)
-                        .setSize(LARGE_BUTTON_SIZE)
+                        .setSize(LARGE_SIZE)
                         .setContentDescription(CONTENT_DESCRIPTION)
                         .build();
 
         assertButton(
                 button,
-                LARGE_BUTTON_SIZE,
-                PRIMARY_BUTTON_COLORS,
+                LARGE_SIZE,
+                PRIMARY_COLORS,
                 CONTENT_DESCRIPTION,
                 Button.METADATA_TAG_ICON,
                 null,
@@ -165,8 +156,8 @@
 
         assertButton(
                 button,
-                DEFAULT_BUTTON_SIZE,
-                PRIMARY_BUTTON_COLORS,
+                DEFAULT_SIZE,
+                PRIMARY_COLORS,
                 CONTENT_DESCRIPTION,
                 Button.METADATA_TAG_ICON,
                 null,
@@ -185,8 +176,8 @@
 
         assertButton(
                 button,
-                DEFAULT_BUTTON_SIZE,
-                PRIMARY_BUTTON_COLORS,
+                DEFAULT_SIZE,
+                PRIMARY_COLORS,
                 CONTENT_DESCRIPTION,
                 Button.METADATA_TAG_TEXT,
                 TEXT,
@@ -201,13 +192,13 @@
                 new Button.Builder(CONTEXT, CLICKABLE)
                         .setTextContent(TEXT)
                         .setContentDescription(CONTENT_DESCRIPTION)
-                        .setSize(EXTRA_LARGE_BUTTON_SIZE)
+                        .setSize(EXTRA_LARGE_SIZE)
                         .build();
 
         assertButton(
                 button,
-                EXTRA_LARGE_BUTTON_SIZE,
-                PRIMARY_BUTTON_COLORS,
+                EXTRA_LARGE_SIZE,
+                PRIMARY_COLORS,
                 CONTENT_DESCRIPTION,
                 Button.METADATA_TAG_TEXT,
                 TEXT,
diff --git a/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/ChipTest.java b/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/ChipTest.java
index 8165be0..4f1fc5f 100644
--- a/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/ChipTest.java
+++ b/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/ChipTest.java
@@ -24,8 +24,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assert.assertThrows;
-
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import android.content.Context;
@@ -75,7 +73,7 @@
         String contentDescription = "Chip";
         Chip chip =
                 new Chip.Builder(CONTEXT, CLICKABLE, DEVICE_PARAMETERS)
-                        .setPrimaryTextContent(MAIN_TEXT)
+                        .setPrimaryLabelContent(MAIN_TEXT)
                         .setHorizontalAlignment(HORIZONTAL_ALIGN_CENTER)
                         .setContentDescription(contentDescription)
                         .build();
@@ -94,18 +92,22 @@
     @Test
     public void testFullChipColors() {
         ChipColors colors = new ChipColors(Color.YELLOW, Color.WHITE, Color.BLUE, Color.MAGENTA);
+        String secondaryLabel = "Label";
         Chip chip =
                 new Chip.Builder(CONTEXT, CLICKABLE, DEVICE_PARAMETERS)
                         .setChipColors(colors)
-                        .setPrimaryTextLabelIconContent(MAIN_TEXT, "Label", "ICON_ID")
+                        .setPrimaryLabelContent(MAIN_TEXT)
+                        .setSecondaryLabelContent(secondaryLabel)
+                        .setIconContent("ICON_ID")
                         .build();
         assertChip(
                 chip,
                 HORIZONTAL_ALIGN_START,
                 colors,
+                MAIN_TEXT + "\n" + secondaryLabel,
                 Chip.METADATA_TAG_ICON,
                 MAIN_TEXT,
-                "Label",
+                secondaryLabel,
                 "ICON_ID",
                 null);
     }
@@ -115,12 +117,13 @@
         Chip chip =
                 new Chip.Builder(CONTEXT, CLICKABLE, DEVICE_PARAMETERS)
                         .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
-                        .setPrimaryTextContent(MAIN_TEXT)
+                        .setPrimaryLabelContent(MAIN_TEXT)
                         .build();
         assertChip(
                 chip,
                 HORIZONTAL_ALIGN_START,
                 ChipDefaults.PRIMARY_COLORS,
+                MAIN_TEXT,
                 Chip.METADATA_TAG_TEXT,
                 MAIN_TEXT,
                 null,
@@ -129,13 +132,6 @@
     }
 
     @Test
-    public void testChipEmptyFails() {
-        assertThrows(
-                IllegalStateException.class,
-                () -> new Chip.Builder(CONTEXT, CLICKABLE, DEVICE_PARAMETERS).build());
-    }
-
-    @Test
     public void testChipCustomContent() {
         ColorProp yellow = argb(Color.YELLOW);
         ColorProp blue = argb(Color.BLUE);
@@ -154,10 +150,12 @@
                                         .build())
                         .build();
 
+        String contentDescription = "Custom chip";
         Chip chip =
                 new Chip.Builder(CONTEXT, CLICKABLE, DEVICE_PARAMETERS)
                         .setCustomContent(content)
                         .setHorizontalAlignment(HORIZONTAL_ALIGN_START)
+                        .setContentDescription(contentDescription)
                         .build();
 
         assertChip(
@@ -166,6 +164,7 @@
                 new ChipColors(
                         ChipDefaults.PRIMARY_COLORS.getBackgroundColor(),
                         new ColorProp.Builder().build()),
+                contentDescription,
                 Chip.METADATA_TAG_CUSTOM_CONTENT,
                 null,
                 null,
@@ -240,27 +239,6 @@
         assertThat(Chip.fromLayoutElement(box)).isNull();
     }
 
-    private void assertChip(
-            @NonNull Chip actualChip,
-            @HorizontalAlignment int hAlign,
-            @NonNull ChipColors colors,
-            @NonNull String expectedMetadata,
-            @Nullable String expectedPrimaryText,
-            @Nullable String expectedLabel,
-            @Nullable String expectedIcon,
-            @Nullable LayoutElement expectedCustomContent) {
-        assertChip(
-                actualChip,
-                hAlign,
-                colors,
-                null,
-                expectedMetadata,
-                expectedPrimaryText,
-                expectedLabel,
-                expectedIcon,
-                expectedCustomContent);
-    }
-
     private void assertFromLayoutElementChipIsEqual(
             @NonNull Chip chip,
             @HorizontalAlignment int hAlign,
@@ -314,15 +292,15 @@
         }
 
         if (expectedPrimaryText == null) {
-            assertThat(actualChip.getPrimaryTextContent()).isNull();
+            assertThat(actualChip.getPrimaryLabelContent()).isNull();
         } else {
-            assertThat(actualChip.getPrimaryTextContent()).isEqualTo(expectedPrimaryText);
+            assertThat(actualChip.getPrimaryLabelContent()).isEqualTo(expectedPrimaryText);
         }
 
         if (expectedLabel == null) {
-            assertThat(actualChip.getLabelContent()).isNull();
+            assertThat(actualChip.getSecondaryLabelContent()).isNull();
         } else {
-            assertThat(actualChip.getLabelContent()).isEqualTo(expectedLabel);
+            assertThat(actualChip.getSecondaryLabelContent()).isEqualTo(expectedLabel);
         }
 
         if (expectedIcon == null) {
diff --git a/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/layouts/ProgressIndicatorLayoutTest.java b/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/layouts/EdgeContentLayoutTest.java
similarity index 63%
rename from wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/layouts/ProgressIndicatorLayoutTest.java
rename to wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/layouts/EdgeContentLayoutTest.java
index ca0a5c2..e4e413a 100644
--- a/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/layouts/ProgressIndicatorLayoutTest.java
+++ b/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/layouts/EdgeContentLayoutTest.java
@@ -41,7 +41,7 @@
 
 @RunWith(AndroidJUnit4.class)
 @DoNotInstrument
-public class ProgressIndicatorLayoutTest {
+public class EdgeContentLayoutTest {
     private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
     private static final DeviceParameters DEVICE_PARAMETERS =
             new DeviceParameters.Builder().setScreenWidthDp(192).setScreenHeightDp(192).build();
@@ -54,10 +54,10 @@
         LayoutElement content = new Box.Builder().build();
         CircularProgressIndicator progressIndicator =
                 new CircularProgressIndicator.Builder().build();
-        ProgressIndicatorLayout layout =
-                new ProgressIndicatorLayout.Builder(DEVICE_PARAMETERS)
+        EdgeContentLayout layout =
+                new EdgeContentLayout.Builder(DEVICE_PARAMETERS)
                         .setContent(content)
-                        .setProgressIndicatorContent(progressIndicator)
+                        .setEdgeContent(progressIndicator)
                         .setPrimaryLabelTextContent(PRIMARY_LABEL)
                         .setSecondaryLabelTextContent(SECONDARY_LABEL)
                         .build();
@@ -68,8 +68,8 @@
     @Test
     public void testContentOnly() {
         LayoutElement content = new Box.Builder().build();
-        ProgressIndicatorLayout layout =
-                new ProgressIndicatorLayout.Builder(DEVICE_PARAMETERS).setContent(content).build();
+        EdgeContentLayout layout =
+                new EdgeContentLayout.Builder(DEVICE_PARAMETERS).setContent(content).build();
 
         assertLayout(layout, null, content, null, null);
     }
@@ -78,9 +78,9 @@
     public void testIndicatorOnly() {
         CircularProgressIndicator progressIndicator =
                 new CircularProgressIndicator.Builder().build();
-        ProgressIndicatorLayout layout =
-                new ProgressIndicatorLayout.Builder(DEVICE_PARAMETERS)
-                        .setProgressIndicatorContent(progressIndicator)
+        EdgeContentLayout layout =
+                new EdgeContentLayout.Builder(DEVICE_PARAMETERS)
+                        .setEdgeContent(progressIndicator)
                         .build();
 
         assertLayout(layout, progressIndicator, null, null, null);
@@ -88,8 +88,7 @@
 
     @Test
     public void testEmpty() {
-        ProgressIndicatorLayout layout =
-                new ProgressIndicatorLayout.Builder(DEVICE_PARAMETERS).build();
+        EdgeContentLayout layout = new EdgeContentLayout.Builder(DEVICE_PARAMETERS).build();
 
         assertLayout(layout, null, null, null, null);
     }
@@ -98,53 +97,53 @@
     public void testWrongElement() {
         Column box = new Column.Builder().build();
 
-        assertThat(ProgressIndicatorLayout.fromLayoutElement(box)).isNull();
+        assertThat(EdgeContentLayout.fromLayoutElement(box)).isNull();
     }
 
     @Test
     public void testWrongBox() {
         Box box = new Box.Builder().build();
 
-        assertThat(ProgressIndicatorLayout.fromLayoutElement(box)).isNull();
+        assertThat(EdgeContentLayout.fromLayoutElement(box)).isNull();
     }
 
     @Test
     public void testWrongTag() {
         Box box =
                 new Box.Builder()
-                    .setModifiers(
-                        new Modifiers.Builder()
-                            .setMetadata(
-                                new ElementMetadata.Builder()
-                                    .setTagData("test".getBytes(UTF_8))
-                                    .build())
-                            .build())
-                    .build();
+                        .setModifiers(
+                                new Modifiers.Builder()
+                                        .setMetadata(
+                                                new ElementMetadata.Builder()
+                                                        .setTagData("test".getBytes(UTF_8))
+                                                        .build())
+                                        .build())
+                        .build();
 
-        assertThat(ProgressIndicatorLayout.fromLayoutElement(box)).isNull();
+        assertThat(EdgeContentLayout.fromLayoutElement(box)).isNull();
     }
 
     @Test
     public void testWrongLengthTag() {
         Box box =
                 new Box.Builder()
-                    .setModifiers(
-                        new Modifiers.Builder()
-                            .setMetadata(
-                                new ElementMetadata.Builder()
-                                    .setTagData(
-                                        ProgressIndicatorLayout
-                                            .METADATA_TAG_PREFIX
-                                            .getBytes(UTF_8))
-                                    .build())
-                            .build())
-                    .build();
+                        .setModifiers(
+                                new Modifiers.Builder()
+                                        .setMetadata(
+                                                new ElementMetadata.Builder()
+                                                        .setTagData(
+                                                                EdgeContentLayout
+                                                                        .METADATA_TAG_PREFIX
+                                                                        .getBytes(UTF_8))
+                                                        .build())
+                                        .build())
+                        .build();
 
-        assertThat(ProgressIndicatorLayout.fromLayoutElement(box)).isNull();
+        assertThat(EdgeContentLayout.fromLayoutElement(box)).isNull();
     }
 
     private void assertLayout(
-            @NonNull ProgressIndicatorLayout actualLayout,
+            @NonNull EdgeContentLayout actualLayout,
             @Nullable LayoutElement expectedProgressIndicator,
             @Nullable LayoutElement expectedContent,
             @Nullable LayoutElement expectedPrimaryLabel,
@@ -158,8 +157,7 @@
 
         Box box = new Box.Builder().addContent(actualLayout).build();
 
-        ProgressIndicatorLayout newLayout =
-                ProgressIndicatorLayout.fromLayoutElement(box.getContents().get(0));
+        EdgeContentLayout newLayout = EdgeContentLayout.fromLayoutElement(box.getContents().get(0));
 
         assertThat(newLayout).isNotNull();
         assertLayoutIsEqual(
@@ -169,26 +167,26 @@
                 expectedPrimaryLabel,
                 expectedSecondaryLabel);
 
-        assertThat(ProgressIndicatorLayout.fromLayoutElement(actualLayout)).isEqualTo(actualLayout);
+        assertThat(EdgeContentLayout.fromLayoutElement(actualLayout)).isEqualTo(actualLayout);
     }
 
     private void assertLayoutIsEqual(
-            @NonNull ProgressIndicatorLayout actualLayout,
+            @NonNull EdgeContentLayout actualLayout,
             @Nullable LayoutElement expectedProgressIndicator,
             @Nullable LayoutElement expectedContent,
             @Nullable LayoutElement expectedPrimaryLabel,
             @Nullable LayoutElement expectedSecondaryLabel) {
-        byte[] expectedMetadata = ProgressIndicatorLayout.METADATA_TAG_BASE.clone();
+        byte[] expectedMetadata = EdgeContentLayout.METADATA_TAG_BASE.clone();
 
         if (expectedProgressIndicator == null) {
-            assertThat(actualLayout.getProgressIndicatorContent()).isNull();
+            assertThat(actualLayout.getEdgeContent()).isNull();
         } else {
-            assertThat(actualLayout.getProgressIndicatorContent().toLayoutElementProto())
+            assertThat(actualLayout.getEdgeContent().toLayoutElementProto())
                     .isEqualTo(expectedProgressIndicator.toLayoutElementProto());
-            expectedMetadata[ProgressIndicatorLayout.FLAG_INDEX] =
+            expectedMetadata[EdgeContentLayout.FLAG_INDEX] =
                     (byte)
-                            (expectedMetadata[ProgressIndicatorLayout.FLAG_INDEX]
-                                    | ProgressIndicatorLayout.PROGRESS_INDICATOR_PRESENT);
+                            (expectedMetadata[EdgeContentLayout.FLAG_INDEX]
+                                    | EdgeContentLayout.EDGE_CONTENT_PRESENT);
         }
 
         if (expectedContent == null) {
@@ -196,10 +194,10 @@
         } else {
             assertThat(actualLayout.getContent().toLayoutElementProto())
                     .isEqualTo(expectedContent.toLayoutElementProto());
-            expectedMetadata[ProgressIndicatorLayout.FLAG_INDEX] =
+            expectedMetadata[EdgeContentLayout.FLAG_INDEX] =
                     (byte)
-                            (expectedMetadata[ProgressIndicatorLayout.FLAG_INDEX]
-                                    | ProgressIndicatorLayout.CONTENT_PRESENT);
+                            (expectedMetadata[EdgeContentLayout.FLAG_INDEX]
+                                    | EdgeContentLayout.CONTENT_PRESENT);
         }
 
         if (expectedPrimaryLabel == null) {
@@ -207,10 +205,10 @@
         } else {
             assertThat(actualLayout.getPrimaryLabelTextContent().toLayoutElementProto())
                     .isEqualTo(expectedPrimaryLabel.toLayoutElementProto());
-            expectedMetadata[ProgressIndicatorLayout.FLAG_INDEX] =
+            expectedMetadata[EdgeContentLayout.FLAG_INDEX] =
                     (byte)
-                            (expectedMetadata[ProgressIndicatorLayout.FLAG_INDEX]
-                                    | ProgressIndicatorLayout.PRIMARY_LABEL_PRESENT);
+                            (expectedMetadata[EdgeContentLayout.FLAG_INDEX]
+                                    | EdgeContentLayout.PRIMARY_LABEL_PRESENT);
         }
 
         if (expectedSecondaryLabel == null) {
@@ -218,10 +216,10 @@
         } else {
             assertThat(actualLayout.getSecondaryLabelTextContent().toLayoutElementProto())
                     .isEqualTo(expectedSecondaryLabel.toLayoutElementProto());
-            expectedMetadata[ProgressIndicatorLayout.FLAG_INDEX] =
+            expectedMetadata[EdgeContentLayout.FLAG_INDEX] =
                     (byte)
-                            (expectedMetadata[ProgressIndicatorLayout.FLAG_INDEX]
-                                    | ProgressIndicatorLayout.SECONDARY_LABEL_PRESENT);
+                            (expectedMetadata[EdgeContentLayout.FLAG_INDEX]
+                                    | EdgeContentLayout.SECONDARY_LABEL_PRESENT);
         }
 
         assertThat(actualLayout.getMetadataTag()).isEqualTo(expectedMetadata);
diff --git a/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/layouts/MultiButtonLayoutTest.java b/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/layouts/MultiButtonLayoutTest.java
index ad69ff6..ec35b24 100644
--- a/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/layouts/MultiButtonLayoutTest.java
+++ b/wear/tiles/tiles-material/src/test/java/androidx/wear/tiles/material/layouts/MultiButtonLayoutTest.java
@@ -58,7 +58,7 @@
         Button button1 =
                 new Button.Builder(CONTEXT, CLICKABLE)
                         .setTextContent("1")
-                        .setSize(ButtonDefaults.EXTRA_LARGE_BUTTON_SIZE)
+                        .setSize(ButtonDefaults.EXTRA_LARGE_SIZE)
                         .build();
 
         MultiButtonLayout layout =
diff --git a/wear/watchface/watchface-client-guava/lint-baseline.xml b/wear/watchface/watchface-client-guava/lint-baseline.xml
index da107d2..1b26322 100644
--- a/wear/watchface/watchface-client-guava/lint-baseline.xml
+++ b/wear/watchface/watchface-client-guava/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/wear/watchface/watchface-client/lint-baseline.xml b/wear/watchface/watchface-client/lint-baseline.xml
deleted file mode 100644
index 99afe84..0000000
--- a/wear/watchface/watchface-client/lint-baseline.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 27 (current min is 26): `WatchFaceControlService`"
-        errorLine1="    private val realService = object : WatchFaceControlService() {"
-        errorLine2="                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlTestService.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Extending WatchFaceControlService requires API level 27 (current min is 26): `WatchFaceControlService`"
-        errorLine1="    private val realService = object : WatchFaceControlService() {"
-        errorLine2="                                       ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlTestService.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 27 (current min is 26): `IWatchFaceInstanceServiceStub`"
-        errorLine1="            object : IWatchFaceInstanceServiceStub("
-        errorLine2="            ^">
-        <location
-            file="src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlTestService.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Extending IWatchFaceInstanceServiceStub requires API level 27 (current min is 26): `IWatchFaceInstanceServiceStub`"
-        errorLine1="            object : IWatchFaceInstanceServiceStub("
-        errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/wear/watchface/client/test/WatchFaceControlTestService.kt"/>
-    </issue>
-
-</issues>
diff --git a/wear/watchface/watchface-complications-data/lint-baseline.xml b/wear/watchface/watchface-complications-data/lint-baseline.xml
index 5e94cbd..1c2886d 100644
--- a/wear/watchface/watchface-complications-data/lint-baseline.xml
+++ b/wear/watchface/watchface-complications-data/lint-baseline.xml
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_short_days&quot; formatted=&quot;false&quot; msgid=&quot;3878057769320887026&quot;>"
         errorLine2="    ^">
         <location
@@ -12,7 +12,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_short_days&quot; formatted=&quot;false&quot; msgid=&quot;3878057769320887026&quot;>"
         errorLine2="    ^">
         <location
@@ -21,7 +21,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_short_hours&quot; formatted=&quot;false&quot; msgid=&quot;6016687406802669982&quot;>"
         errorLine2="    ^">
         <location
@@ -30,7 +30,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_short_hours&quot; formatted=&quot;false&quot; msgid=&quot;6016687406802669982&quot;>"
         errorLine2="    ^">
         <location
@@ -39,7 +39,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_short_minutes&quot; formatted=&quot;false&quot; msgid=&quot;6752732458902810711&quot;>"
         errorLine2="    ^">
         <location
@@ -48,7 +48,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_short_minutes&quot; formatted=&quot;false&quot; msgid=&quot;6752732458902810711&quot;>"
         errorLine2="    ^">
         <location
@@ -57,7 +57,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_words_days&quot; formatted=&quot;false&quot; msgid=&quot;5109682345086392533&quot;>"
         errorLine2="    ^">
         <location
@@ -66,7 +66,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_words_days&quot; formatted=&quot;false&quot; msgid=&quot;5109682345086392533&quot;>"
         errorLine2="    ^">
         <location
@@ -75,7 +75,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_words_hours&quot; formatted=&quot;false&quot; msgid=&quot;3172220157267000186&quot;>"
         errorLine2="    ^">
         <location
@@ -84,7 +84,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_words_hours&quot; formatted=&quot;false&quot; msgid=&quot;3172220157267000186&quot;>"
         errorLine2="    ^">
         <location
@@ -93,7 +93,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_words_minutes&quot; formatted=&quot;false&quot; msgid=&quot;529404827937478243&quot;>"
         errorLine2="    ^">
         <location
@@ -102,7 +102,7 @@
 
     <issue
         id="MissingQuantity"
-        message="For locale &quot;fr&quot; (French) the following quantities should also be defined: `many`"
+        message="For locale &quot;fr&quot; (French) the following quantity should also be defined: `many` (e.g. &quot;1000000 de jours&quot;)"
         errorLine1="    &lt;plurals name=&quot;time_difference_words_minutes&quot; formatted=&quot;false&quot; msgid=&quot;529404827937478243&quot;>"
         errorLine2="    ^">
         <location
diff --git a/wear/watchface/watchface-data/lint-baseline.xml b/wear/watchface/watchface-data/lint-baseline.xml
deleted file mode 100644
index 11bdc2c..0000000
--- a/wear/watchface/watchface-data/lint-baseline.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  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.
-  -->
-
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NullabilityAnnotationsDetector"
-        message="Use @androidx.annotation.NonNull instead of @org.jetbrains.annotations.NotNull"
-        errorLine1="    @NotNull"
-        errorLine2="    ~~~~~~~~">
-        <location
-            file="src/main/java/android/support/wearable/watchface/accessibility/ContentDescriptionLabel.java"/>
-    </issue>
-
-</issues>
\ No newline at end of file
diff --git a/wear/watchface/watchface-guava/lint-baseline.xml b/wear/watchface/watchface-guava/lint-baseline.xml
deleted file mode 100644
index fca58a1..0000000
--- a/wear/watchface/watchface-guava/lint-baseline.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 27 (current min is 26): `WatchFaceControlService`"
-        errorLine1="    private val realService = object : WatchFaceControlService() {"
-        errorLine2="                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlTestService.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Extending WatchFaceControlService requires API level 27 (current min is 26): `WatchFaceControlService`"
-        errorLine1="    private val realService = object : WatchFaceControlService() {"
-        errorLine2="                                       ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlTestService.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 27 (current min is 26): `IWatchFaceInstanceServiceStub`"
-        errorLine1="            object : IWatchFaceInstanceServiceStub("
-        errorLine2="            ^">
-        <location
-            file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlTestService.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Extending IWatchFaceInstanceServiceStub requires API level 27 (current min is 26): `IWatchFaceInstanceServiceStub`"
-        errorLine1="            object : IWatchFaceInstanceServiceStub("
-        errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlTestService.kt"/>
-    </issue>
-
-</issues>
diff --git a/wear/watchface/watchface/lint-baseline.xml b/wear/watchface/watchface/lint-baseline.xml
deleted file mode 100644
index fe2d397..0000000
--- a/wear/watchface/watchface/lint-baseline.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 27 (current min is 26): `dump`"
-        errorLine1="        HeadlessWatchFaceImpl.dump(indentingPrintWriter)"
-        errorLine2="                              ~~~~">
-        <location
-            file="src/main/java/androidx/wear/watchface/WatchFaceService.kt"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            complicationSlotsManager.watchState,"
-        errorLine2="                                     ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/wear/watchface/ComplicationSlot.kt"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                            if (engine.deferredWatchFaceImpl.isCompleted) {"
-        errorLine2="                                       ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/wear/watchface/control/InteractiveInstanceManager.kt"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                    it.deferredWatchFaceImpl.await()"
-        errorLine2="                       ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/wear/watchface/control/InteractiveWatchFaceImpl.kt"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                return engine.deferredWatchFaceImpl.await().WFEditorDelegate()"
-        errorLine2="                              ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/wear/watchface/WatchFace.kt"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                return engine.deferredWatchFaceImpl.await().WFEditorDelegate()"
-        errorLine2="                              ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/wear/watchface/WatchFace.kt"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                complicationSlotsManager.watchState = watchState"
-        errorLine2="                                         ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/wear/watchface/WatchFaceService.kt"/>
-    </issue>
-
-</issues>
diff --git a/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/test/XmlDefinedUserStyleSchemaAndComplicationSlotsTest.kt b/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/test/XmlDefinedUserStyleSchemaAndComplicationSlotsTest.kt
index abdd4b3..85ac2af 100644
--- a/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/test/XmlDefinedUserStyleSchemaAndComplicationSlotsTest.kt
+++ b/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/test/XmlDefinedUserStyleSchemaAndComplicationSlotsTest.kt
@@ -250,10 +250,10 @@
             val slotA = watchFaceImpl.complicationSlotsManager.complicationSlots[10]!!
             assertThat(slotA.boundsType).isEqualTo(ComplicationSlotBoundsType.ROUND_RECT)
             assertThat(slotA.supportedTypes).containsExactly(
-                ComplicationType.SHORT_TEXT,
                 ComplicationType.RANGED_VALUE,
+                ComplicationType.SHORT_TEXT,
                 ComplicationType.SMALL_IMAGE
-            )
+            ).inOrder()
             assertThat(slotA.defaultDataSourcePolicy.primaryDataSource).isNull()
             assertThat(slotA.defaultDataSourcePolicy.primaryDataSourceDefaultType)
                 .isNull()
@@ -279,8 +279,8 @@
             val slotB = watchFaceImpl.complicationSlotsManager.complicationSlots[20]!!
             assertThat(slotB.boundsType).isEqualTo(ComplicationSlotBoundsType.BACKGROUND)
             assertThat(slotB.supportedTypes).containsExactly(
-                ComplicationType.SHORT_TEXT, ComplicationType.LONG_TEXT
-            )
+                ComplicationType.LONG_TEXT, ComplicationType.SHORT_TEXT
+            ).inOrder()
             assertThat(slotB.defaultDataSourcePolicy.primaryDataSource).isEqualTo(
                 ComponentName("com.package", "com.app")
             )
diff --git a/wear/watchface/watchface/src/androidTest/res/xml/xml_watchface.xml b/wear/watchface/watchface/src/androidTest/res/xml/xml_watchface.xml
index 0c5e885..12adaf5 100644
--- a/wear/watchface/watchface/src/androidTest/res/xml/xml_watchface.xml
+++ b/wear/watchface/watchface/src/androidTest/res/xml/xml_watchface.xml
@@ -46,7 +46,7 @@
         app:name="@string/complication_name_one"
         app:screenReaderName="@string/complication_screen_reader_name_one"
         app:boundsType="ROUND_RECT"
-        app:supportedTypes="SHORT_TEXT|RANGED_VALUE|SMALL_IMAGE"
+        app:supportedTypes="RANGED_VALUE|SHORT_TEXT|SMALL_IMAGE"
         app:systemDataSourceFallback="DATA_SOURCE_WATCH_BATTERY"
         app:systemDataSourceFallbackDefaultType="RANGED_VALUE">
         <ComplicationSlotBounds app:left="0.3" app:top="0.7" app:right="0.7" app:bottom="0.9"/>
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
index a046124..3e2674e 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
@@ -330,8 +330,10 @@
         internal const val MAX_REASONABLE_SCHEMA_WIRE_SIZE_BYTES = 50000
 
         /** The maximum reasonable wire size for an Icon in a [UserStyleSchema] in pixels. */
-        @Px internal const val MAX_REASONABLE_SCHEMA_ICON_WIDTH = 400
-        @Px internal const val MAX_REASONABLE_SCHEMA_ICON_HEIGHT = 400
+        @Px
+        internal const val MAX_REASONABLE_SCHEMA_ICON_WIDTH = 400
+        @Px
+        internal const val MAX_REASONABLE_SCHEMA_ICON_HEIGHT = 400
 
         /** @hide */
         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -407,19 +409,20 @@
 
     private val
         xmlSchemaAndComplicationSlotsDefinition: XmlSchemaAndComplicationSlotsDefinition by lazy {
-            val resourceId = getXmlWatchFaceResourceId()
-            if (resourceId == 0) {
-                XmlSchemaAndComplicationSlotsDefinition(
-                    schema = null,
-                    complicationSlots = emptyList(),
-                    flavors = null)
-            } else {
-                XmlSchemaAndComplicationSlotsDefinition.inflate(
-                    resources,
-                    resources.getXml(resourceId)
-                )
-            }
+        val resourceId = getXmlWatchFaceResourceId()
+        if (resourceId == 0) {
+            XmlSchemaAndComplicationSlotsDefinition(
+                schema = null,
+                complicationSlots = emptyList(),
+                flavors = null
+            )
+        } else {
+            XmlSchemaAndComplicationSlotsDefinition.inflate(
+                resources,
+                resources.getXml(resourceId)
+            )
         }
+    }
 
     /**
      * If the WatchFaceService's manifest doesn't define a
@@ -473,8 +476,10 @@
      */
     @Deprecated(
         "Use the version with currentUserStyleRepository argument instead",
-        ReplaceWith("getComplicationSlotInflationFactory" +
-            "(currentUserStyleRepository: CurrentUserStyleRepository)")
+        ReplaceWith(
+            "getComplicationSlotInflationFactory" +
+                "(currentUserStyleRepository: CurrentUserStyleRepository)"
+        )
     )
     @WorkerThread
     protected open fun getComplicationSlotInflationFactory(): ComplicationSlotInflationFactory? =
@@ -501,7 +506,8 @@
         getComplicationSlotInflationFactory()
             ?: throw NotImplementedError(
                 "You must override WatchFaceService.getComplicationSlotInflationFactory " +
-                "to provide additional details needed to inflate ComplicationSlotsManager")
+                    "to provide additional details needed to inflate ComplicationSlotsManager"
+            )
 
     /**
      * If the WatchFaceService's manifest doesn't define a
@@ -609,8 +615,7 @@
                     "WatchFaceBackground",
                     Process.THREAD_PRIORITY_FOREGROUND // The user is waiting on WF init.
                 ).apply {
-                    uncaughtExceptionHandler = Thread.UncaughtExceptionHandler {
-                            _, throwable ->
+                    uncaughtExceptionHandler = Thread.UncaughtExceptionHandler { _, throwable ->
                         Log.e(TAG, "Uncaught exception on watch face background thread", throwable)
                     }
                     start()
@@ -651,6 +656,8 @@
         }
     }
 
+    internal open fun cancelCoroutineScopesInOnDestroy() = true
+
     /**
      * This is open for use by tests, it allows them to inject a custom [SurfaceHolder].
      * @hide
@@ -1066,7 +1073,9 @@
         private val uiThreadHandler: Handler,
         private val backgroundThreadHandler: Handler,
         headless: Boolean
-    ) : WallpaperService.Engine(), WatchFaceHostApi {
+    ) : WallpaperService.Engine(),
+        WatchFaceHostApi,
+        AccessibilityManager.AccessibilityStateChangeListener {
         internal val backgroundThreadCoroutineScope =
             CoroutineScope(backgroundThreadHandler.asCoroutineDispatcher().immediate)
 
@@ -1123,6 +1132,7 @@
         internal var destroyed = false
         internal var surfaceDestroyed = false
         internal var pendingComplicationDataCacheWrite = false
+        internal var systemViewOfContentDescriptionLabelsIsStale = false
 
         internal lateinit var ambientUpdateWakelock: PowerManager.WakeLock
 
@@ -1562,10 +1572,11 @@
             if (this::interactiveInstanceId.isInitialized) {
                 InteractiveInstanceManager.deleteInstance(interactiveInstanceId)
             }
+            stopListeningForAccessibilityStateChanges()
 
             // NB user code could throw an exception so do this last.
-            runBlocking {
-                try {
+            try {
+                runBlocking {
                     // The WatchFaceImpl is created on the UiThread so if we get here and it's not
                     // created we can be sure it'll never be created hence we don't need to destroy
                     // it.
@@ -1576,17 +1587,34 @@
                         watchFaceInitDetails
                             .await().watchFace.renderer.onDestroy()
                     }
-                } catch (e: Exception) {
-                    // Throwing an exception here leads to a cascade of errors, log instead.
-                    Log.e(
-                        TAG,
-                        "WatchFace exception observed in onDestroy (may have occurred during init)",
-                        e
-                    )
+                }
+            } catch (e: Exception) {
+                // Throwing an exception here leads to a cascade of errors, log instead.
+                Log.e(
+                    TAG,
+                    "WatchFace exception observed in onDestroy (may have occurred during init)",
+                    e
+                )
+            } finally {
+                if (this@EngineWrapper::ambientUpdateWakelock.isInitialized) {
+                    // Make sure the WakeLock doesn't retain the WatchFaceService.
+                    ambientUpdateWakelock.release()
+                }
+
+                // StateFlows may retain WatchFaceService via the coroutineScope. Call cancel to
+                // ensure resources are released. Headless watch faces call cancelCoroutineScopes
+                // themselves since they call onDestroy from a coroutine context.
+                if (cancelCoroutineScopesInOnDestroy() && !mutableWatchState.isHeadless) {
+                    cancelCoroutineScopes()
                 }
             }
         }
 
+        internal fun cancelCoroutineScopes() {
+            uiThreadCoroutineScope.cancel()
+            backgroundThreadCoroutineScope.cancel()
+        }
+
         override fun onSurfaceDestroyed(holder: SurfaceHolder) {
             surfaceDestroyed = true
         }
@@ -2012,11 +2040,13 @@
                 !isPreAndroidR()
             )
 
-            // There's no point creating BroadcastsReceiver for headless instances.
+            // There's no point creating BroadcastsReceiver or listening for Accessibility state
+            // changes if this is a headless instance.
             val broadcastsReceiver = TraceEvent("create BroadcastsReceiver").use {
                 if (watchState.isHeadless) {
                     null
                 } else {
+                    startListeningForAccessibilityStateChanges()
                     BroadcastsReceiver(_context, broadcastsObserver).apply {
                         processBatteryStatus(
                             IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { iFilter ->
@@ -2302,6 +2332,24 @@
             wslFlow.setActiveComplications(complicationSlotIds)
         }
 
+        internal fun startListeningForAccessibilityStateChanges() {
+            val accessibilityManager =
+                getSystemService(ACCESSIBILITY_SERVICE) as AccessibilityManager
+            accessibilityManager.addAccessibilityStateChangeListener(this)
+        }
+
+        internal fun stopListeningForAccessibilityStateChanges() {
+            val accessibilityManager =
+                getSystemService(ACCESSIBILITY_SERVICE) as AccessibilityManager
+            accessibilityManager.removeAccessibilityStateChangeListener(this)
+        }
+
+        override fun onAccessibilityStateChanged(isEnabled: Boolean) {
+            if (systemViewOfContentDescriptionLabelsIsStale && isEnabled) {
+                maybeSendContentDescriptionLabelsBroadcast()
+            }
+        }
+
         @UiThread
         override fun updateContentDescriptionLabels() {
             val labels = mutableListOf<Pair<Int, ContentDescriptionLabel>>()
@@ -2380,20 +2428,26 @@
                     contentDescriptionLabels =
                         labels.sortedBy { it.first }.map { it.second }.toTypedArray()
 
-                    // From Android R Let SysUI know the labels have changed if the accessibility
-                    // manager is enabled.
-                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
-                        getAccessibilityManager().isEnabled
-                    ) {
-                        // TODO(alexclarke): This should require a permission. See http://b/184717802
-                        _context.sendBroadcast(
-                            Intent(Constants.ACTION_WATCH_FACE_REFRESH_A11Y_LABELS)
-                        )
-                    }
+                    systemViewOfContentDescriptionLabelsIsStale = true
+                    maybeSendContentDescriptionLabelsBroadcast()
                 }
             }
         }
 
+        /**
+         * From Android R lets SysUI know the labels have changed, if the AccessibilityManager is
+         * enabled.
+         */
+        private fun maybeSendContentDescriptionLabelsBroadcast() {
+            if (!isPreAndroidR() && getAccessibilityManager().isEnabled) {
+                // TODO(alexclarke): This should require a permission. See http://b/184717802
+                _context.sendBroadcast(
+                    Intent(Constants.ACTION_WATCH_FACE_REFRESH_A11Y_LABELS)
+                )
+                systemViewOfContentDescriptionLabelsIsStale = false
+            }
+        }
+
         private fun getAccessibilityManager() =
             _context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
 
@@ -2426,6 +2480,10 @@
             writer.println("createdBy=$createdBy")
             writer.println("watchFaceInitStarted=$wslFlow.watchFaceInitStarted")
             writer.println("asyncWatchFaceConstructionPending=$asyncWatchFaceConstructionPending")
+            writer.println(
+                "systemViewOfContentDescriptionLabelsIsStale=" +
+                    systemViewOfContentDescriptionLabelsIsStale
+            )
 
             if (this::interactiveInstanceId.isInitialized) {
                 writer.println("interactiveInstanceId=$interactiveInstanceId")
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/XmlSchemaAndComplicationSlotsDefinition.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/XmlSchemaAndComplicationSlotsDefinition.kt
index 149d0b1..c447a36 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/XmlSchemaAndComplicationSlotsDefinition.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/XmlSchemaAndComplicationSlotsDefinition.kt
@@ -104,6 +104,17 @@
         val boundingArc: BoundingArc?
     ) {
         companion object {
+            private val typesMap by lazy(LazyThreadSafetyMode.NONE) {
+                mapOf(
+                    "SHORT_TEXT" to ComplicationType.SHORT_TEXT,
+                    "LONG_TEXT" to ComplicationType.LONG_TEXT,
+                    "RANGED_VALUE" to ComplicationType.RANGED_VALUE,
+                    "MONOCHROMATIC_IMAGE" to ComplicationType.MONOCHROMATIC_IMAGE,
+                    "SMALL_IMAGE" to ComplicationType.SMALL_IMAGE,
+                    "PHOTO_IMAGE" to ComplicationType.PHOTO_IMAGE
+                )
+            }
+
             fun inflate(
                 resources: Resources,
                 parser: XmlResourceParser
@@ -142,25 +153,11 @@
                     "A ComplicationSlot must have a supportedTypes attribute"
                 }
                 val supportedTypes =
-                    parser.getAttributeIntValue(NAMESPACE_APP, "supportedTypes", 0)
-                val supportedTypesList = ArrayList<ComplicationType>()
-                if ((supportedTypes and 0x1) != 0) {
-                    supportedTypesList.add(ComplicationType.SHORT_TEXT)
-                }
-                if ((supportedTypes and 0x2) != 0) {
-                    supportedTypesList.add(ComplicationType.LONG_TEXT)
-                }
-                if ((supportedTypes and 0x4) != 0) {
-                    supportedTypesList.add(ComplicationType.RANGED_VALUE)
-                }
-                if ((supportedTypes and 0x8) != 0) {
-                    supportedTypesList.add(ComplicationType.MONOCHROMATIC_IMAGE)
-                }
-                if ((supportedTypes and 0x10) != 0) {
-                    supportedTypesList.add(ComplicationType.SMALL_IMAGE)
-                }
-                if ((supportedTypes and 0x20) != 0) {
-                    supportedTypesList.add(ComplicationType.PHOTO_IMAGE)
+                    parser.getAttributeValue(NAMESPACE_APP, "supportedTypes").split('|')
+                val supportedTypesList = supportedTypes.map {
+                    typesMap[it] ?: throw IllegalArgumentException(
+                        "Unrecognised type $it for ComplicationSlot $slotId"
+                    )
                 }
 
                 val defaultComplicationDataSourcePolicy =
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/HeadlessWatchFaceImpl.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/HeadlessWatchFaceImpl.kt
index 337750d..f558093 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/HeadlessWatchFaceImpl.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/HeadlessWatchFaceImpl.kt
@@ -135,7 +135,8 @@
                         watchFaceService = null
                     }
                 }
-            }
+                engineCopy
+            }.cancelCoroutineScopes()
         }
     }
 }
diff --git a/wear/watchface/watchface/src/main/res/values/attrs.xml b/wear/watchface/watchface/src/main/res/values/attrs.xml
index a759be4..e7ccef4 100644
--- a/wear/watchface/watchface/src/main/res/values/attrs.xml
+++ b/wear/watchface/watchface/src/main/res/values/attrs.xml
@@ -101,15 +101,10 @@
             <enum name="EDGE" value="2" />
         </attr>
 
-        <!-- Required. The ComplicationTypes accepted by this complication slot. -->
-        <attr name="supportedTypes">
-            <flag name="SHORT_TEXT" value="0x1" />
-            <flag name="LONG_TEXT" value="0x2" />
-            <flag name="RANGED_VALUE" value="0x4" />
-            <flag name="MONOCHROMATIC_IMAGE" value="0x8" />
-            <flag name="SMALL_IMAGE" value="0x10" />
-            <flag name="PHOTO_IMAGE" value="0x20" />
-        </attr>
+        <!-- Required. The ComplicationTypes accepted by this complication slot.
+        Can be list of SHORT_TEXT, LONG_TEXT, RANGED_VALUE, MONOCHROMATIC_IMAGE,
+        SMALL_IMAGE and PHOTO_IMAGE with | delimiter. -->
+        <attr name="supportedTypes" format="string"/>
 
         <attr name="primaryDataSource"/>
         <attr name="primaryDataSourceDefaultType"/>
diff --git a/wear/watchface/watchface/src/main/res/values/config.xml b/wear/watchface/watchface/src/main/res/values/config.xml
index 636a317..5fcaed1 100644
--- a/wear/watchface/watchface/src/main/res/values/config.xml
+++ b/wear/watchface/watchface/src/main/res/values/config.xml
@@ -17,5 +17,5 @@
 
 <resources>
     <bool name="watch_face_instance_service_enabled">false</bool>
-    <integer name="watch_face_xml_version">3</integer>
+    <integer name="watch_face_xml_version">4</integer>
 </resources>
diff --git a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/TestCommon.kt b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
index bad97a4..d550bab 100644
--- a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
+++ b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
@@ -78,6 +78,12 @@
 
     override fun forceIsVisibleForTesting() = forceIsVisible
 
+    /**
+     * [WatchFaceService.EngineWrapper.onDestroy] is called more than once in some tests which is a
+     * problem due to using a CoroutineScope after it's been cancelled leading to exceptions.
+     */
+    override fun cancelCoroutineScopesInOnDestroy() = false
+
     fun reset() {
         clearTappedState()
         complicationSelected = null
diff --git a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
index d79682e..1cbe519 100644
--- a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
+++ b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
@@ -45,6 +45,7 @@
 import android.view.Surface
 import android.view.SurfaceHolder
 import android.view.WindowInsets
+import android.view.accessibility.AccessibilityManager
 import androidx.annotation.Px
 import androidx.annotation.RequiresApi
 import androidx.test.core.app.ApplicationProvider
@@ -125,6 +126,7 @@
 import org.mockito.Mockito.validateMockitoUsage
 import org.mockito.Mockito.verify
 import org.robolectric.annotation.Config
+import org.robolectric.Shadows.shadowOf
 
 private const val INTERACTIVE_UPDATE_RATE_MS = 16L
 private const val LEFT_COMPLICATION_ID = 1000
@@ -577,7 +579,8 @@
         complicationSlots: List<ComplicationSlot>,
         userStyleSchema: UserStyleSchema,
         wallpaperInteractiveWatchFaceInstanceParams: WallpaperInteractiveWatchFaceInstanceParams,
-        complicationCache: MutableMap<String, ByteArray>? = null
+        complicationCache: MutableMap<String, ByteArray>? = null,
+        preAndroidR: Boolean = false
     ) {
         testWatchFaceService = TestWatchFaceService(
             watchFaceType,
@@ -595,7 +598,7 @@
             watchState,
             handler,
             null,
-            false,
+            preAndroidR,
             null,
             choreographer,
             mockSystemTimeMillis = looperTimeMillis,
@@ -1006,7 +1009,7 @@
     public fun lowestIdComplicationSelectedWhenMarginsOverlap() {
         val complication100 =
             ComplicationSlot.createRoundRectComplicationSlotBuilder(
-            100,
+                100,
                 { watchState, listener ->
                     CanvasComplicationDrawable(complicationDrawableLeft, watchState, listener)
                 },
@@ -3820,6 +3823,67 @@
     }
 
     @Test
+    public fun onAccessibilityStateChanged_preAndroidR() {
+        initWallpaperInteractiveWatchFaceInstance(
+            WatchFaceType.ANALOG,
+            listOf(leftComplication, rightComplication),
+            UserStyleSchema(emptyList()),
+            WallpaperInteractiveWatchFaceInstanceParams(
+                "TestID",
+                DeviceConfig(
+                    false,
+                    false,
+                    0,
+                    0
+                ),
+                WatchUiState(false, 0),
+                UserStyle(emptyMap()).toWireFormat(),
+                emptyList()
+            ),
+            preAndroidR = true
+        )
+
+        engineWrapper.systemViewOfContentDescriptionLabelsIsStale = true
+        val shadowAccessibilityManager =
+            shadowOf(context.getSystemService(AccessibilityManager::class.java))
+
+        // Pre-R nothing should happen when the AccessibilityManager is enabled.
+        shadowAccessibilityManager.setEnabled(true)
+        assertThat(engineWrapper.systemViewOfContentDescriptionLabelsIsStale).isTrue()
+    }
+
+    @Test
+    public fun onAccessibilityStateChanged_androidR_or_above() {
+        initWallpaperInteractiveWatchFaceInstance(
+            WatchFaceType.ANALOG,
+            listOf(leftComplication, rightComplication),
+            UserStyleSchema(emptyList()),
+            WallpaperInteractiveWatchFaceInstanceParams(
+                "TestID",
+                DeviceConfig(
+                    false,
+                    false,
+                    0,
+                    0
+                ),
+                WatchUiState(false, 0),
+                UserStyle(emptyMap()).toWireFormat(),
+                emptyList()
+            ),
+            preAndroidR = false
+        )
+
+        engineWrapper.systemViewOfContentDescriptionLabelsIsStale = true
+        val shadowAccessibilityManager =
+            shadowOf(context.getSystemService(AccessibilityManager::class.java))
+
+        // From R enabling the AccessibilityManager should trigger a broadcast and reset
+        // systemViewOfContentDescriptionLabelsIsStale.
+        shadowAccessibilityManager.setEnabled(true)
+        assertThat(engineWrapper.systemViewOfContentDescriptionLabelsIsStale).isFalse()
+    }
+
+    @Test
     public fun contentDescriptionLabels_contains_ComplicationData() {
         initWallpaperInteractiveWatchFaceInstance(
             WatchFaceType.ANALOG,
diff --git a/wear/wear-ongoing/lint-baseline.xml b/wear/wear-ongoing/lint-baseline.xml
deleted file mode 100644
index bbb03df..0000000
--- a/wear/wear-ongoing/lint-baseline.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(StaticIconResourceId, received.staticIcon.resId)"
-        errorLine2="                                                               ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(AnimatedIconResourceId, received.animatedIcon!!.resId)"
-        errorLine2="                                                                     ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(StaticIconResourceId, received.staticIcon.resId)"
-        errorLine2="                                                               ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(AnimatedIconResourceId, received.animatedIcon!!.resId)"
-        errorLine2="                                                                     ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(StaticIconResourceId, received.staticIcon.resId)"
-        errorLine2="                                                               ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(AnimatedIconResourceId, received.animatedIcon!!.resId)"
-        errorLine2="                                                                     ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(StaticIconResourceId, received.staticIcon.resId)"
-        errorLine2="                                                               ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(AnimatedIconResourceId, received.animatedIcon!!.resId)"
-        errorLine2="                                                                     ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(StaticIconResourceId, received.staticIcon.resId)"
-        errorLine2="                                                               ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(StaticIconResourceId, received.staticIcon.resId)"
-        errorLine2="                                                               ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(newAnimatedIconResourceId, received.animatedIcon!!.resId)"
-        errorLine2="                                                                        ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 25): `android.graphics.drawable.Icon#getResId`"
-        errorLine1="        assertEquals(newStaticIconResourceId, received.staticIcon.resId)"
-        errorLine2="                                                                  ~~~~~">
-        <location
-            file="src/test/java/androidx/wear/ongoing/OngoingActivityTest.kt"/>
-    </issue>
-
-</issues>
diff --git a/webkit/webkit/lint-baseline.xml b/webkit/webkit/lint-baseline.xml
index 9f0f85f..fbb2079 100644
--- a/webkit/webkit/lint-baseline.xml
+++ b/webkit/webkit/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha08)" variant="all" version="7.3.0-alpha08">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="NewApi"
diff --git a/webkit/webkit/src/main/java/androidx/webkit/internal/WebMessageAdapter.java b/webkit/webkit/src/main/java/androidx/webkit/internal/WebMessageAdapter.java
index 7d2e940..a65f15a 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/internal/WebMessageAdapter.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/internal/WebMessageAdapter.java
@@ -37,12 +37,19 @@
         this.mWebMessageCompat = webMessage;
     }
 
+    @SuppressWarnings("deprecation")
     @Override
     @Nullable
     public String getData() {
         return mWebMessageCompat.getData();
     }
 
+    @SuppressWarnings("MissingOverride")
+    @Nullable
+    public InvocationHandler getMessagePayload() {
+        throw new UnsupportedOperationException("This method is not yet supported");
+    }
+
     @Override
     @Nullable
     public InvocationHandler[] getPorts() {
@@ -72,6 +79,10 @@
      * {@link WebMessageCompat} objects - a class apps recognize.
      */
     @NonNull
+    // Suppress deprecation warning for usage of WebMessageBoundaryInterface's getData() method,
+    // TODO([email protected]): remove this once changes corresponding to https://crrev.com/c/3607795
+    // are done in webkit.
+    @SuppressWarnings("deprecation")
     public static WebMessageCompat webMessageCompatFromBoundaryInterface(
             @NonNull WebMessageBoundaryInterface boundaryInterface) {
         return new WebMessageCompat(boundaryInterface.getData(),
diff --git a/window/extensions/extensions/lint-baseline.xml b/window/extensions/extensions/lint-baseline.xml
deleted file mode 100644
index 9a822c3..0000000
--- a/window/extensions/extensions/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 17 (current min is 14): `android.view.View#generateViewId`"
-        errorLine1="        mRootViewId = View.generateViewId();"
-        errorLine2="                           ~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/window/extensions/TestActivity.java"/>
-    </issue>
-
-</issues>
diff --git a/work/work-inspection/lint-baseline.xml b/work/work-inspection/lint-baseline.xml
index a73862a..518945a 100644
--- a/work/work-inspection/lint-baseline.xml
+++ b/work/work-inspection/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="RemoveWorkManagerInitializer"
diff --git a/work/work-multiprocess/lint-baseline.xml b/work/work-multiprocess/lint-baseline.xml
index 5bfeb59..17feda2 100644
--- a/work/work-multiprocess/lint-baseline.xml
+++ b/work/work-multiprocess/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
diff --git a/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt b/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt
index 99806fa..330da1c 100644
--- a/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt
+++ b/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteCoroutineWorkerTest.kt
@@ -163,7 +163,8 @@
             mTaskExecutor,
             mForegroundProcessor,
             mDatabase,
-            mDatabase.workSpecDao().getWorkSpec(request.stringId)!!
+            mDatabase.workSpecDao().getWorkSpec(request.stringId)!!,
+            emptyList()
         ).build()
     }
 }
diff --git a/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteListenableWorkerTest.kt b/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteListenableWorkerTest.kt
index 337878a..7a62ee7 100644
--- a/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteListenableWorkerTest.kt
+++ b/work/work-multiprocess/src/androidTest/java/androidx/work/multiprocess/RemoteListenableWorkerTest.kt
@@ -188,7 +188,8 @@
             mTaskExecutor,
             mForegroundProcessor,
             mDatabase,
-            mDatabase.workSpecDao().getWorkSpec(request.stringId)!!
+            mDatabase.workSpecDao().getWorkSpec(request.stringId)!!,
+            emptyList()
         ).build()
     }
 
diff --git a/work/work-runtime-ktx/lint-baseline.xml b/work/work-runtime-ktx/lint-baseline.xml
index 67d7223..1a8a9a7 100644
--- a/work/work-runtime-ktx/lint-baseline.xml
+++ b/work/work-runtime-ktx/lint-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
 
     <issue
         id="UnknownNullness"
diff --git a/work/work-runtime/lint-baseline.xml b/work/work-runtime/lint-baseline.xml
index e7fa03a..f683ddb 100644
--- a/work/work-runtime/lint-baseline.xml
+++ b/work/work-runtime/lint-baseline.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
+<issues format="6" by="lint 7.4.0-alpha05" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha05)" variant="all" version="7.4.0-alpha05">
+
     <issue
         id="BanSynchronizedMethods"
         message="Use of synchronized methods is not recommended"
@@ -71,4 +72,5 @@
         <location
             file="src/main/java/androidx/work/impl/utils/futures/SettableFuture.java"/>
     </issue>
+
 </issues>
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/WorkUpdateTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/WorkUpdateTest.kt
index 21cd4ba..a1ff449 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/WorkUpdateTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/WorkUpdateTest.kt
@@ -75,9 +75,10 @@
     val workManager = WorkManagerImpl(
         context, configuration, taskExecutor, db, schedulers, processor, trackers
     )
+    val greedyScheduler = GreedyScheduler(context, configuration, trackers, workManager)
 
     init {
-        schedulers.add(GreedyScheduler(context, configuration, trackers, workManager))
+        schedulers.add(greedyScheduler)
         WorkManagerImpl.setDelegate(workManager)
     }
 
@@ -168,6 +169,34 @@
 
     @Test
     @MediumTest
+    fun updateTagsWhileRunning() {
+        val request = OneTimeWorkRequest.Builder(TestWorker::class.java)
+            .setConstraints(Constraints(requiresCharging = true))
+            .addTag("original").build()
+        workManager.enqueue(request).result.get()
+        val serialExecutorBlocker = CountDownLatch(1)
+        // stop any execution on serialTaskExecutor
+        taskExecutor.serialTaskExecutor.execute {
+            serialExecutorBlocker.await()
+        }
+        // will add startWork task to the serialTaskExecutor queue
+        greedyScheduler.onAllConstraintsMet(listOf(request.workSpec))
+        val updatedRequest = OneTimeWorkRequest.Builder(TestWorker::class.java)
+            .setConstraints(Constraints(requiresCharging = true))
+            .setId(request.id)
+            .addTag("updated")
+            .build()
+        // will add update task to the serialTaskExecutor queue
+        val updateResult = workManager.updateWork(updatedRequest)
+        serialExecutorBlocker.countDown()
+        val worker = workerFactory.awaitWorker(request.id)
+        assertThat(worker.tags).contains("original")
+        assertThat(worker.tags).doesNotContain("updated")
+        assertThat(updateResult.get()).isEqualTo(APPLIED_FOR_NEXT_RUN)
+    }
+
+    @Test
+    @MediumTest
     fun updateWorkerClass() {
         // requiresCharging constraint is faked, so it will never be satisfied
         val oneTimeWorkRequest = OneTimeWorkRequest.Builder(TestWorker::class.java)
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/ControlledWorkerWrapperTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/ControlledWorkerWrapperTest.kt
index a9141a5..6e80617 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/ControlledWorkerWrapperTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/ControlledWorkerWrapperTest.kt
@@ -136,7 +136,8 @@
             taskExecutor,
             NoOpForegroundProcessor,
             workDatabase,
-            workDatabase.workSpecDao().getWorkSpec(id)!!
+            workDatabase.workSpecDao().getWorkSpec(id)!!,
+            emptyList()
         ).build()
     }
 }
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkContinuationImplTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkContinuationImplTest.java
index be2df12..aef0621 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkContinuationImplTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkContinuationImplTest.java
@@ -315,7 +315,8 @@
                 new InstantWorkTaskExecutor(),
                 foregroundProcessor,
                 mDatabase,
-                workSpecDao.getWorkSpec(joinId))
+                workSpecDao.getWorkSpec(joinId),
+                new ArrayList<>())
                 .build()
                 .run();
 
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
index b138562..a652619 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/WorkerWrapperTest.java
@@ -1228,7 +1228,8 @@
                 mWorkTaskExecutor,
                 mMockForegroundProcessor,
                 mDatabase,
-                mWorkSpecDao.getWorkSpec(work.getStringId())
+                mWorkSpecDao.getWorkSpec(work.getStringId()),
+                mDatabase.workTagDao().getTagsForWorkSpecId(work.getStringId())
         ).build();
 
         FutureListener listener = createAndAddFutureListener(workerWrapper);
@@ -1278,7 +1279,9 @@
                 mWorkTaskExecutor,
                 mMockForegroundProcessor,
                 mDatabase,
-                mWorkSpecDao.getWorkSpec(work.getStringId())).build();
+                mWorkSpecDao.getWorkSpec(work.getStringId()),
+                mDatabase.workTagDao().getWorkSpecIdsWithTag(work.getStringId())
+                ).build();
 
         workerWrapper.interrupt();
         workerWrapper.run();
@@ -1305,7 +1308,9 @@
                 mWorkTaskExecutor,
                 mMockForegroundProcessor,
                 mDatabase,
-                mWorkSpecDao.getWorkSpec(workSpecId));
+                mWorkSpecDao.getWorkSpec(workSpecId),
+                mDatabase.workTagDao().getWorkSpecIdsWithTag(workSpecId)
+        );
     }
 
     private FutureListener createAndAddFutureListener(WorkerWrapper workerWrapper) {
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
index 74e5983..3465172 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
@@ -28,9 +28,11 @@
 import androidx.work.Configuration
 import androidx.work.Constraints
 import androidx.work.ForegroundInfo
+import androidx.work.ListenableWorker
 import androidx.work.NetworkType
 import androidx.work.OneTimeWorkRequest
 import androidx.work.WorkInfo
+import androidx.work.WorkerParameters
 import androidx.work.impl.Processor
 import androidx.work.impl.Scheduler
 import androidx.work.impl.WorkDatabase
@@ -45,9 +47,11 @@
 import androidx.work.impl.foreground.SystemForegroundDispatcher.createStopForegroundIntent
 import androidx.work.impl.utils.StopWorkRunnable
 import androidx.work.impl.utils.SynchronousExecutor
+import androidx.work.impl.utils.futures.SettableFuture
 import androidx.work.impl.utils.taskexecutor.InstantWorkTaskExecutor
 import androidx.work.impl.utils.taskexecutor.TaskExecutor
 import androidx.work.worker.TestWorker
+import com.google.common.util.concurrent.ListenableFuture
 import org.hamcrest.CoreMatchers.`is`
 import org.hamcrest.MatcherAssert.assertThat
 import org.junit.Before
@@ -127,11 +131,12 @@
 
     @Test
     fun testStartForeground_trackConstraints_workSpecHasConstraints() {
-        val request = OneTimeWorkRequest.Builder(TestWorker::class.java)
+        val request = OneTimeWorkRequest.Builder(NeverResolvedWorker::class.java)
             .setConstraints(
                 Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
             ).build()
         workDatabase.workSpecDao().insertWorkSpec(request.workSpec)
+        processor.startWork(StartStopToken(WorkGenerationalId(request.stringId, 0)))
         val notificationId = 1
         val notification = mock(Notification::class.java)
         val metadata = ForegroundInfo(notificationId, notification)
@@ -338,11 +343,12 @@
 
     @Test
     fun testStartForeground_trackConstraints_constraintsUnMet() {
-        val request = OneTimeWorkRequest.Builder(TestWorker::class.java)
+        val request = OneTimeWorkRequest.Builder(NeverResolvedWorker::class.java)
             .setConstraints(
                 Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
             ).build()
         workDatabase.workSpecDao().insertWorkSpec(request.workSpec)
+        processor.startWork(StartStopToken(WorkGenerationalId(request.stringId, 0)))
         val notificationId = 1
         val notification = mock(Notification::class.java)
         val metadata = ForegroundInfo(notificationId, notification)
@@ -358,11 +364,12 @@
 
     @Test
     fun testCancelForegroundWork() {
-        val request = OneTimeWorkRequest.Builder(TestWorker::class.java)
+        val request = OneTimeWorkRequest.Builder(NeverResolvedWorker::class.java)
             .setConstraints(
                 Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
             ).build()
         workDatabase.workSpecDao().insertWorkSpec(request.workSpec)
+        processor.startWork(StartStopToken(WorkGenerationalId(request.stringId, 0)))
         val notificationId = 1
         val notification = mock(Notification::class.java)
         val metadata = ForegroundInfo(notificationId, notification)
@@ -401,4 +408,33 @@
         verify(workManager, times(1)).cancelWorkById(eq(UUID.fromString(request.workSpec.id)))
         assertThat(processor.hasWork(), `is`(false))
     }
+
+    @Test
+    fun testUseRunningWork() {
+        val request = OneTimeWorkRequest.Builder(NeverResolvedWorker::class.java)
+            .setConstraints(Constraints(requiredNetworkType = NetworkType.CONNECTED))
+            .build()
+        workDatabase.workSpecDao().insertWorkSpec(request.workSpec)
+        processor.startWork(StartStopToken(WorkGenerationalId(request.stringId, 0)))
+        val updatedRequest = OneTimeWorkRequest.Builder(NeverResolvedWorker::class.java)
+            .setId(request.id)
+            .build()
+        workDatabase.workSpecDao().updateWorkSpec(updatedRequest.workSpec)
+        val notificationId = 1
+        val notification = mock(Notification::class.java)
+        val metadata = ForegroundInfo(notificationId, notification)
+        val intent = createStartForegroundIntent(context,
+            WorkGenerationalId(request.stringId, 0), metadata)
+        dispatcher.onStartCommand(intent)
+        verify(tracker, times(1)).replace(setOf(request.workSpec))
+    }
+}
+
+class NeverResolvedWorker(
+    context: Context,
+    workerParams: WorkerParameters
+) : ListenableWorker(context, workerParams) {
+    override fun startWork(): ListenableFuture<Result> {
+        return SettableFuture.create()
+    }
 }
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/WorkerWrapperForegroundTest.kt b/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/WorkerWrapperForegroundTest.kt
index 01ce6aa..6b0ae8d 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/WorkerWrapperForegroundTest.kt
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/foreground/WorkerWrapperForegroundTest.kt
@@ -122,7 +122,8 @@
             taskExecutor,
             foregroundProcessor,
             workDatabase,
-            workDatabase.workSpecDao().getWorkSpec(request.stringId)!!
+            workDatabase.workSpecDao().getWorkSpec(request.stringId)!!,
+            emptyList()
         ).build()
 
         wrapper.run()
@@ -144,7 +145,8 @@
             taskExecutor,
             foregroundProcessor,
             workDatabase,
-            workDatabase.workSpecDao().getWorkSpec(request.stringId)!!
+            workDatabase.workSpecDao().getWorkSpec(request.stringId)!!,
+            emptyList()
         ).build()
 
         wrapper.run()
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
index 6d9facb..d5380aa 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/workers/ConstraintTrackingWorkerTest.java
@@ -81,6 +81,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
@@ -364,7 +365,8 @@
                 mWorkTaskExecutor,
                 mForegroundProcessor,
                 mDatabase,
-                mDatabase.workSpecDao().getWorkSpec(mWork.getStringId())
+                mDatabase.workSpecDao().getWorkSpec(mWork.getStringId()),
+                new ArrayList<>()
         );
     }
 
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/Processor.java b/work/work-runtime/src/main/java/androidx/work/impl/Processor.java
index d0f1479..72e52a3 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/Processor.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/Processor.java
@@ -116,8 +116,13 @@
             @NonNull StartStopToken startStopToken,
             @Nullable WorkerParameters.RuntimeExtras runtimeExtras) {
         WorkGenerationalId id = startStopToken.getId();
+        String workSpecId = id.getWorkSpecId();
+        ArrayList<String> tags = new ArrayList<>();
         WorkSpec workSpec = mWorkDatabase.runInTransaction(
-                () -> mWorkDatabase.workSpecDao().getWorkSpec(id.getWorkSpecId())
+                () -> {
+                    tags.addAll(mWorkDatabase.workTagDao().getTagsForWorkSpecId(workSpecId));
+                    return mWorkDatabase.workSpecDao().getWorkSpec(workSpecId);
+                }
         );
         if (workSpec == null) {
             Logger.get().warning(TAG, "Didn't find WorkSpec for id " + id);
@@ -128,7 +133,6 @@
         synchronized (mLock) {
             // Work may get triggered multiple times if they have passing constraints
             // and new work with those constraints are added.
-            String workSpecId = id.getWorkSpecId();
             if (isEnqueued(workSpecId)) {
                 // there must be another run if it is enqueued.
                 Set<StartStopToken> tokens = mWorkRuns.get(workSpecId);
@@ -164,7 +168,8 @@
                             mWorkTaskExecutor,
                             this,
                             mWorkDatabase,
-                            workSpec)
+                            workSpec,
+                            tags)
                             .withSchedulers(mSchedulers)
                             .withRuntimeExtras(runtimeExtras)
                             .build();
@@ -382,6 +387,26 @@
         }
     }
 
+    /**
+     * Returns a spec of the running worker by the given id
+     *
+     * @param workSpecId id of running worker
+     */
+    @Nullable
+    public WorkSpec getRunningWorkSpec(@NonNull String workSpecId) {
+        synchronized (mLock) {
+            WorkerWrapper workerWrapper = mForegroundWorkMap.get(workSpecId);
+            if (workerWrapper == null) {
+                workerWrapper = mEnqueuedWorkMap.get(workSpecId);
+            }
+            if (workerWrapper != null) {
+                return workerWrapper.getWorkSpec();
+            } else {
+                return null;
+            }
+        }
+    }
+
     private void runOnExecuted(@NonNull final WorkGenerationalId id, boolean needsReschedule) {
         mWorkTaskExecutor.getMainThreadExecutor().execute(
                 () -> onExecuted(id, needsReschedule)
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.java b/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.java
index 78f014f..b2a0d12 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/WorkerWrapper.java
@@ -48,7 +48,6 @@
 import androidx.work.impl.model.WorkGenerationalId;
 import androidx.work.impl.model.WorkSpec;
 import androidx.work.impl.model.WorkSpecDao;
-import androidx.work.impl.model.WorkTagDao;
 import androidx.work.impl.utils.PackageManagerHelper;
 import androidx.work.impl.utils.SynchronousExecutor;
 import androidx.work.impl.utils.WorkForegroundRunnable;
@@ -97,7 +96,6 @@
     private WorkDatabase mWorkDatabase;
     private WorkSpecDao mWorkSpecDao;
     private DependencyDao mDependencyDao;
-    private WorkTagDao mWorkTagDao;
 
     private List<String> mTags;
     private String mWorkDescription;
@@ -128,7 +126,7 @@
         mWorkDatabase = builder.mWorkDatabase;
         mWorkSpecDao = mWorkDatabase.workSpecDao();
         mDependencyDao = mWorkDatabase.dependencyDao();
-        mWorkTagDao = mWorkDatabase.workTagDao();
+        mTags = builder.mTags;
     }
 
     @NonNull
@@ -143,11 +141,15 @@
     @WorkerThread
     @Override
     public void run() {
-        mTags = mWorkTagDao.getTagsForWorkSpecId(mWorkSpecId);
         mWorkDescription = createWorkDescription(mTags);
         runWorker();
     }
 
+    @NonNull
+    public WorkSpec getWorkSpec() {
+        return mWorkSpec;
+    }
+
     private void runWorker() {
         if (tryCheckForInterruptionAndResolve()) {
             return;
@@ -639,6 +641,7 @@
         @NonNull WorkDatabase mWorkDatabase;
         @NonNull WorkSpec mWorkSpec;
         List<Scheduler> mSchedulers;
+        private final List<String> mTags;
         @NonNull
         WorkerParameters.RuntimeExtras mRuntimeExtras = new WorkerParameters.RuntimeExtras();
 
@@ -647,13 +650,16 @@
                 @NonNull TaskExecutor workTaskExecutor,
                 @NonNull ForegroundProcessor foregroundProcessor,
                 @NonNull WorkDatabase database,
-                @NonNull WorkSpec workSpec) {
+                @NonNull WorkSpec workSpec,
+                @NonNull List<String> tags
+        ) {
             mAppContext = context.getApplicationContext();
             mWorkTaskExecutor = workTaskExecutor;
             mForegroundProcessor = foregroundProcessor;
             mConfiguration = configuration;
             mWorkDatabase = database;
             mWorkSpec = workSpec;
+            mTags = tags;
         }
 
         /**
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java b/work/work-runtime/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java
index e2a9335..4890888 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java
@@ -35,7 +35,6 @@
 import androidx.work.ForegroundInfo;
 import androidx.work.Logger;
 import androidx.work.impl.ExecutionListener;
-import androidx.work.impl.WorkDatabase;
 import androidx.work.impl.WorkManagerImpl;
 import androidx.work.impl.constraints.WorkConstraintsCallback;
 import androidx.work.impl.constraints.WorkConstraintsTracker;
@@ -239,11 +238,10 @@
     private void handleStartForeground(@NonNull Intent intent) {
         Logger.get().info(TAG, "Started foreground service " + intent);
         final String workSpecId = intent.getStringExtra(KEY_WORKSPEC_ID);
-        final WorkDatabase database = mWorkManagerImpl.getWorkDatabase();
         mTaskExecutor.executeOnTaskThread(new Runnable() {
             @Override
             public void run() {
-                WorkSpec workSpec = database.workSpecDao().getWorkSpec(workSpecId);
+                WorkSpec workSpec = mWorkManagerImpl.getProcessor().getRunningWorkSpec(workSpecId);
                 // Only track constraints if there are constraints that need to be tracked
                 // (constraints are immutable)
                 if (workSpec != null && workSpec.hasConstraints()) {
diff --git a/work/work-testing/lint-baseline.xml b/work/work-testing/lint-baseline.xml
deleted file mode 100644
index 62fa67c..0000000
--- a/work/work-testing/lint-baseline.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.3.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (7.3.0-alpha07)" variant="all" version="7.3.0-alpha07">
-</issues>