Merge "Update Picker API for contentDescription following review." into androidx-main
diff --git a/appcompat/appcompat/api/restricted_current.txt b/appcompat/appcompat/api/restricted_current.txt
index 6287496..cfb6629 100644
--- a/appcompat/appcompat/api/restricted_current.txt
+++ b/appcompat/appcompat/api/restricted_current.txt
@@ -575,7 +575,6 @@
     ctor public ContextThemeWrapper();
     ctor public ContextThemeWrapper(android.content.Context!, @StyleRes int);
     ctor public ContextThemeWrapper(android.content.Context!, android.content.res.Resources.Theme!);
-    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public ContextThemeWrapper(android.content.Context!, int, boolean);
     method public void applyOverrideConfiguration(android.content.res.Configuration!);
     method public int getThemeResId();
     method protected void onApplyThemeResource(android.content.res.Resources.Theme!, int, boolean);
diff --git a/appcompat/appcompat/src/androidTest/AndroidManifest.xml b/appcompat/appcompat/src/androidTest/AndroidManifest.xml
index 792dca7..7749326 100644
--- a/appcompat/appcompat/src/androidTest/AndroidManifest.xml
+++ b/appcompat/appcompat/src/androidTest/AndroidManifest.xml
@@ -273,16 +273,6 @@
             android:configChanges="uiMode"/>
 
         <activity
-            android:name="androidx.appcompat.app.NightModeRotationConfigChangesActivityA"
-            android:theme="@style/Theme.AppCompat.DayNight"
-            android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|fontScale|uiMode|mcc|mnc"
-            android:screenOrientation="portrait" />
-
-        <activity
-            android:name="androidx.appcompat.app.NightModeRotationConfigChangesActivityB"
-            android:screenOrientation="landscape" />
-
-        <activity
             android:name="androidx.appcompat.app.NightModeRotateDoesNotRecreateActivity"
             android:theme="@style/Theme.AppCompat.DayNight"
             android:configChanges="orientation|screenSize"/>
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotationConfigChangesActivityA.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotationConfigChangesActivityA.java
deleted file mode 100644
index 9c30029..0000000
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotationConfigChangesActivityA.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.appcompat.app;
-
-import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES;
-
-import android.os.Bundle;
-
-import androidx.annotation.RequiresApi;
-
-/**
- * An activity.
- */
-@RequiresApi(17)
-public class NightModeRotationConfigChangesActivityA extends NightModeActivity {
-
-    @Override
-    public void onCreate(Bundle bundle) {
-        AppCompatDelegate.setDefaultNightMode(MODE_NIGHT_YES);
-
-        super.onCreate(bundle);
-    }
-}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotationConfigChangesTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotationConfigChangesTestCase.kt
deleted file mode 100644
index 636f963..0000000
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotationConfigChangesTestCase.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.appcompat.app
-
-import android.app.Instrumentation
-import android.app.Instrumentation.ActivityMonitor
-import android.content.Intent
-import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
-import android.content.res.Configuration.UI_MODE_NIGHT_MASK
-import android.content.res.Configuration.UI_MODE_NIGHT_YES
-import androidx.activity.ComponentActivity
-import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
-import androidx.lifecycle.Lifecycle
-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 org.junit.After
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotNull
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@LargeTest
-@RunWith(AndroidJUnit4::class)
-public class NightModeRotationConfigChangesTestCase {
-
-    @Before
-    public fun setup() {
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            AppCompatDelegate.setDefaultNightMode(MODE_NIGHT_FOLLOW_SYSTEM)
-        }
-    }
-
-    @After
-    public fun teardown() {
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            AppCompatDelegate.setDefaultNightMode(MODE_NIGHT_FOLLOW_SYSTEM)
-        }
-    }
-
-    /**
-     * Regression test for activities that specify a default night mode outside of attachBaseContext
-     * and handle uiMode configuration changes.
-     */
-    @Test
-    @SdkSuppress(minSdkVersion = 17)
-    public fun testDefaultNightModeWithHandledRotation() {
-        val instr = InstrumentationRegistry.getInstrumentation()
-        val result = Instrumentation.ActivityResult(0, Intent())
-        val monitorA = ActivityMonitor(
-            NightModeRotationConfigChangesActivityA::class.java.name, result, false
-        )
-        val monitorB = ActivityMonitor(
-            NightModeRotationConfigChangesActivityB::class.java.name, result, false
-        )
-        instr.addMonitor(monitorA)
-        instr.addMonitor(monitorB)
-
-        // Start activity A, which sets default night mode YES in onCreate.
-        instr.startActivitySync(
-            Intent(instr.context, NightModeRotationConfigChangesActivityA::class.java).apply {
-                flags = FLAG_ACTIVITY_NEW_TASK
-            }
-        )
-        val activityA = monitorA.waitForActivityWithTimeout(3000) as NightModeActivity
-        assertNotNull(activityA)
-        waitUntilState(activityA, Lifecycle.State.RESUMED)
-
-        // Check that the initial state is correct.
-        assertEquals(
-            UI_MODE_NIGHT_YES,
-            activityA.resources.configuration.uiMode and UI_MODE_NIGHT_MASK
-        )
-
-        // Start activity B, which forces the device into landscape mode.
-        instr.startActivitySync(
-            Intent(instr.context, NightModeRotationConfigChangesActivityB::class.java).apply {
-                flags = FLAG_ACTIVITY_NEW_TASK
-            }
-        )
-        val activityB = monitorB.waitForActivityWithTimeout(3000) as ComponentActivity
-        assertNotNull(activityB)
-        waitUntilState(activityB, Lifecycle.State.RESUMED)
-
-        // Activity A is hidden, wait for it to stop.
-        waitUntilState(activityA, Lifecycle.State.CREATED)
-
-        // Stop Activity B and wait for it to be destroyed.
-        instr.runOnMainSync {
-            activityB.finish()
-        }
-        waitUntilState(activityB, Lifecycle.State.DESTROYED)
-
-        // Wait for Activity A to resume.
-        waitUntilState(activityA, Lifecycle.State.RESUMED)
-
-        // Check that the final state is correct.
-        assertEquals(
-            UI_MODE_NIGHT_YES,
-            activityA.resources.configuration.uiMode and UI_MODE_NIGHT_MASK
-        )
-    }
-}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
index 3cd8711..8219742 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
@@ -366,7 +366,7 @@
         if (sCanApplyOverrideConfiguration
                 && baseContext instanceof android.view.ContextThemeWrapper) {
             final Configuration config = createOverrideConfigurationForDayNight(
-                    baseContext, modeToApply, null, false);
+                    baseContext, modeToApply, null);
             if (DEBUG) {
                 Log.d(TAG, String.format("Attempting to apply config to base context: %s",
                         config.toString()));
@@ -386,7 +386,7 @@
         // Again, but using the AppCompat version of ContextThemeWrapper.
         if (baseContext instanceof ContextThemeWrapper) {
             final Configuration config = createOverrideConfigurationForDayNight(
-                    baseContext, modeToApply, null, false);
+                    baseContext, modeToApply, null);
             if (DEBUG) {
                 Log.d(TAG, String.format("Attempting to apply config to base context: %s",
                         config.toString()));
@@ -443,7 +443,7 @@
         }
 
         final Configuration config = createOverrideConfigurationForDayNight(
-                baseContext, modeToApply, configOverlay, true);
+                baseContext, modeToApply, configOverlay);
         if (DEBUG) {
             Log.d(TAG, String.format("Applying night mode using ContextThemeWrapper and "
                     + "applyOverrideConfiguration(). Config: %s", config.toString()));
@@ -452,7 +452,7 @@
         // Next, we'll wrap the base context to ensure any method overrides or themes are left
         // intact. Since ThemeOverlay.AppCompat theme is empty, we'll get the base context's theme.
         final ContextThemeWrapper wrappedContext = new ContextThemeWrapper(baseContext,
-                R.style.Theme_AppCompat_Empty, isActivityManifestHandlingUiMode(baseContext));
+                R.style.Theme_AppCompat_Empty);
         wrappedContext.applyOverrideConfiguration(config);
 
         // Check whether the base context has an explicit theme or is able to obtain one
@@ -2464,7 +2464,7 @@
     @NonNull
     private Configuration createOverrideConfigurationForDayNight(
             @NonNull Context context, @ApplyableNightMode final int mode,
-            @Nullable Configuration configOverlay, boolean ignoreFollowSystem) {
+            @Nullable Configuration configOverlay) {
         int newNightMode;
         switch (mode) {
             case MODE_NIGHT_YES:
@@ -2475,15 +2475,11 @@
                 break;
             default:
             case MODE_NIGHT_FOLLOW_SYSTEM:
-                if (ignoreFollowSystem) {
-                    newNightMode = 0;
-                } else {
-                    // If we're following the system, we just use the system default from the
-                    // application context
-                    final Configuration appConfig =
-                            context.getApplicationContext().getResources().getConfiguration();
-                    newNightMode = appConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
-                }
+                // If we're following the system, we just use the system default from the
+                // application context
+                final Configuration appConfig =
+                        context.getApplicationContext().getResources().getConfiguration();
+                newNightMode = appConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
                 break;
         }
 
@@ -2512,7 +2508,7 @@
         boolean handled = false;
 
         final Configuration overrideConfig =
-                createOverrideConfigurationForDayNight(mContext, mode, null, false);
+                createOverrideConfigurationForDayNight(mContext, mode, null);
 
         final boolean activityHandlingUiMode = isActivityManifestHandlingUiMode(mContext);
         final Configuration currentConfiguration = mEffectiveConfiguration == null
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/view/ContextThemeWrapper.java b/appcompat/appcompat/src/main/java/androidx/appcompat/view/ContextThemeWrapper.java
index d605d75..56d9ec7 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/view/ContextThemeWrapper.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/view/ContextThemeWrapper.java
@@ -16,8 +16,6 @@
 
 package androidx.appcompat.view;
 
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.res.AssetManager;
@@ -28,7 +26,6 @@
 
 import androidx.annotation.DoNotInline;
 import androidx.annotation.RequiresApi;
-import androidx.annotation.RestrictTo;
 import androidx.annotation.StyleRes;
 import androidx.appcompat.R;
 
@@ -36,9 +33,6 @@
  * A context wrapper that allows you to modify or replace the theme of the wrapped context.
  */
 public class ContextThemeWrapper extends ContextWrapper {
-    private final boolean mCheckedHandlesConfigChanges;
-    private final boolean mHandlesConfigChanges;
-
     private int mThemeResource;
     private Resources.Theme mTheme;
     private LayoutInflater mInflater;
@@ -54,9 +48,6 @@
      */
     public ContextThemeWrapper() {
         super(null);
-
-        mCheckedHandlesConfigChanges = false;
-        mHandlesConfigChanges = false;
     }
 
     /**
@@ -73,9 +64,6 @@
     public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
         super(base);
         mThemeResource = themeResId;
-
-        mCheckedHandlesConfigChanges = false;
-        mHandlesConfigChanges = false;
     }
 
     /**
@@ -90,29 +78,6 @@
     public ContextThemeWrapper(Context base, Resources.Theme theme) {
         super(base);
         mTheme = theme;
-
-        mCheckedHandlesConfigChanges = false;
-        mHandlesConfigChanges = false;
-    }
-
-    /**
-     * Creates a new context wrapper with the specified theme.
-     *
-     * @param base the base context
-     * @param themeResId the resource ID of the theme to be applied on top of
-     *                   the base context's theme
-     * @param handlesConfigChanges whether the host Activity handles configuration
-     *                             changes relevant (e.g. uiMode, locale) to AppCompat
-     *
-     * @hide For internal use only.
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    public ContextThemeWrapper(Context base, int themeResId, boolean handlesConfigChanges) {
-        super(base);
-        mThemeResource = themeResId;
-
-        mCheckedHandlesConfigChanges = true;
-        mHandlesConfigChanges = handlesConfigChanges;
     }
 
     @Override
@@ -150,7 +115,7 @@
         if (mResources == null) {
             if (mOverrideConfiguration == null) {
                 mResources = super.getResources();
-            } else if (Build.VERSION.SDK_INT >= 17 && shouldUseManagedResources()) {
+            } else if (Build.VERSION.SDK_INT >= 17) {
                 final Context resContext =
                         Api17Impl.createConfigurationContext(this, mOverrideConfiguration);
                 mResources = resContext.getResources();
@@ -164,27 +129,6 @@
         return mResources;
     }
 
-    /**
-     * Returns whether this wrapper should attempt to use a Resources object that receives
-     * updates from the global ResourceManager.
-     * <p>
-     * This is typically only necessary for apps that are handling uiMode or locale changes and are
-     * setting up their custom configuration outside of attachBaseContext, e.g. their initial
-     * wrapper will be created with a default override configuration.
-     */
-    private boolean shouldUseManagedResources() {
-        return !(mCheckedHandlesConfigChanges && mHandlesConfigChanges
-                && isDefaultConfiguration(mOverrideConfiguration));
-    }
-
-    /**
-     * Returns whether the parts of the Configuration that we care about (locale and uiMode) are set
-     * to their default values.
-     */
-    private static boolean isDefaultConfiguration(Configuration config) {
-        return config.uiMode == 0 && config.locale == null;
-    }
-
     @Override
     public void setTheme(int resid) {
         if (mThemeResource != resid) {
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt b/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
index ee4b2ca..bc4aa42 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/dackka/DackkaTask.kt
@@ -112,6 +112,7 @@
                 "sourceRoots" to listOf(sourcesDir.path),
                 "samples" to listOf(samplesDir.path, frameworkSamplesDir.path),
                 "classpath" to classPath,
+                "documentedVisibilities" to listOf("PUBLIC", "PROTECTED"),
                 "externalDocumentationLinks" to linksMap.map { (name, url) -> mapOf(
                     "url" to url,
                     "packageListUrl" to
diff --git a/busytown/impl/build-metalava-and-androidx.sh b/busytown/impl/build-metalava-and-androidx.sh
index ea69bf2..5023d43 100755
--- a/busytown/impl/build-metalava-and-androidx.sh
+++ b/busytown/impl/build-metalava-and-androidx.sh
@@ -55,7 +55,7 @@
 export METALAVA_REPO="$ROOT_DIR/out/dist/repo/m2repository"
 
 function buildAndroidx() {
-  ./frameworks/support/gradlew --ci -p frameworks/support $androidxArguments \
+  ./frameworks/support/busytown/impl/build.sh $androidxArguments \
     --dependency-verification=off # building against tip of tree of metalava that potentially pulls in new dependencies
 
 }
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 e84c886..48349ae 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
@@ -71,6 +71,9 @@
             Manifest.permission.RECORD_AUDIO
         )
 
+    @get:Rule
+    val repeatRule = RepeatRule()
+
     companion object {
         @AfterClass
         @JvmStatic
diff --git a/camera/integration-tests/diagnosetestapp/build.gradle b/camera/integration-tests/diagnosetestapp/build.gradle
index 181ce2a..4060050 100644
--- a/camera/integration-tests/diagnosetestapp/build.gradle
+++ b/camera/integration-tests/diagnosetestapp/build.gradle
@@ -51,7 +51,6 @@
 
     implementation(libs.guavaAndroid)
     implementation(libs.constraintLayout)
-    implementation 'androidx.camera:camera-view:1.1.0-beta03'
 
     compileOnly(libs.kotlinCompiler)
 
diff --git a/camera/integration-tests/diagnosetestapp/src/main/java/androidx/camera/integration/diagnose/MainActivity.kt b/camera/integration-tests/diagnosetestapp/src/main/java/androidx/camera/integration/diagnose/MainActivity.kt
index 8b75c1f..83dbd5f 100644
--- a/camera/integration-tests/diagnosetestapp/src/main/java/androidx/camera/integration/diagnose/MainActivity.kt
+++ b/camera/integration-tests/diagnosetestapp/src/main/java/androidx/camera/integration/diagnose/MainActivity.kt
@@ -17,6 +17,7 @@
 package androidx.camera.integration.diagnose
 
 import android.Manifest
+import android.annotation.SuppressLint
 import android.content.ContentValues
 import android.content.pm.PackageManager
 import android.os.Build
@@ -25,20 +26,29 @@
 import android.util.Log
 import android.widget.Button
 import android.widget.Toast
+import androidx.annotation.OptIn
 import androidx.appcompat.app.AppCompatActivity
 import androidx.camera.core.ImageCapture
 import androidx.camera.core.ImageCaptureException
+import androidx.camera.view.CameraController.IMAGE_CAPTURE
+import androidx.camera.view.CameraController.VIDEO_CAPTURE
 import androidx.camera.view.LifecycleCameraController
 import androidx.camera.view.PreviewView
+import androidx.camera.view.video.ExperimentalVideo
+import androidx.camera.view.video.OnVideoSavedCallback
+import androidx.camera.view.video.OutputFileOptions
+import androidx.camera.view.video.OutputFileResults
 import androidx.core.app.ActivityCompat
 import androidx.core.content.ContextCompat
 import java.text.SimpleDateFormat
 import java.util.Locale
+import java.util.concurrent.Executor
 
 class MainActivity : AppCompatActivity() {
 
     private lateinit var cameraController: LifecycleCameraController
     private lateinit var previewView: PreviewView
+    private lateinit var executor: Executor
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
@@ -46,6 +56,7 @@
         previewView = findViewById(R.id.preview_view)
         cameraController = LifecycleCameraController(this)
         previewView.controller = cameraController
+        executor = ContextCompat.getMainExecutor(this)
         // Request CAMERA permission and fail gracefully if not granted.
         if (allPermissionsGranted()) {
             startCamera()
@@ -56,15 +67,12 @@
         }
         // Setup UI events
         findViewById<Button>(R.id.image_capture).setOnClickListener {
-            // TODO: handle capture button click event following examples
-            //  in CameraControllerFragment.
             Log.d(TAG, "image button clicked")
             takePhoto()
         }
 
         findViewById<Button>(R.id.video_capture).setOnClickListener {
-            // TODO: handle capture button click event following examples
-            //  in CameraControllerFragment.
+            Log.d(TAG, "video button clicked")
             captureVideo()
         }
     }
@@ -97,6 +105,8 @@
     }
 
     private fun takePhoto() {
+        cameraController.setEnabledUseCases(IMAGE_CAPTURE)
+
         val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
             .format(System.currentTimeMillis())
         val contentValues = ContentValues().apply {
@@ -118,7 +128,7 @@
         // been taken
         cameraController.takePicture(
             outputOptions,
-            ContextCompat.getMainExecutor(this),
+            executor,
             object : ImageCapture.OnImageSavedCallback {
                 override fun onError(exc: ImageCaptureException) {
                     val msg = "Photo capture failed: ${exc.message}"
@@ -135,7 +145,65 @@
         )
     }
 
-    private fun captureVideo() {}
+    @SuppressLint("NullAnnotationGroup")
+    @OptIn(ExperimentalVideo::class)
+    private fun captureVideo() {
+        // determine whether the onclick is to start recording or stop recording
+        if (cameraController.isRecording) {
+            cameraController.stopRecording()
+            val msg = "video stopped recording"
+            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
+            Log.d(TAG, msg)
+        } else {
+            // enabling video capture
+            cameraController.setEnabledUseCases(VIDEO_CAPTURE)
+
+            // building file output
+            val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
+                .format(System.currentTimeMillis())
+            val contentValues = ContentValues().apply {
+                put(MediaStore.MediaColumns.DISPLAY_NAME, name)
+                put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
+                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
+                    put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/CameraX-Video")
+                }
+            }
+            val outputFileOptions = OutputFileOptions
+                .builder(contentResolver,
+                    MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+                    contentValues)
+                .build()
+            Log.d(TAG, "finished composing video name")
+
+            // start recording
+            try {
+                cameraController.startRecording(
+                    outputFileOptions,
+                    executor,
+                    object : OnVideoSavedCallback {
+                        override fun onVideoSaved(outputFileResults: OutputFileResults) {
+                            val msg = "Video record succeeded: " + outputFileResults.savedUri
+                            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
+                            Log.d(TAG, msg)
+                        }
+
+                        override fun onError(
+                            videoCaptureError: Int,
+                            message: String,
+                            cause: Throwable?
+                        ) {
+                            Log.e(TAG, "Video saving failed: $message")
+                        }
+                    }
+                )
+                val msg = "video recording"
+                Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
+                Log.d(TAG, msg)
+            } catch (exception: RuntimeException) {
+                Log.e(TAG, "Video failed to record: " + exception.message)
+            }
+        }
+    }
 
     private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
         ContextCompat.checkSelfPermission(
diff --git a/camera/integration-tests/extensionstestapp/build.gradle b/camera/integration-tests/extensionstestapp/build.gradle
index c6a20b0..7d733c7 100644
--- a/camera/integration-tests/extensionstestapp/build.gradle
+++ b/camera/integration-tests/extensionstestapp/build.gradle
@@ -70,6 +70,7 @@
     androidTestImplementation(libs.espressoCore)
     androidTestImplementation(libs.truth)
     androidTestImplementation(project(":camera:camera-testing"))
+    androidTestImplementation(project(":internal-testutils-runtime"))
     androidTestCompileOnly(project(":camera:camera-extensions-stub"))
 
     // Testing resource dependency for manifest
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
new file mode 100644
index 0000000..16dd556
--- /dev/null
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/BindUnbindUseCasesStressTest.kt
@@ -0,0 +1,378 @@
+/*
+ * 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.camera.integration.extensions
+
+import android.content.Context
+import android.graphics.SurfaceTexture
+import android.os.Handler
+import android.os.HandlerThread
+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.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
+import androidx.camera.integration.extensions.util.ExtensionsTestUtil.STRESS_TEST_REPEAT_COUNT
+import androidx.camera.integration.extensions.utils.CameraSelectorUtil
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
+import androidx.camera.testing.GLUtil
+import androidx.camera.testing.SurfaceTextureProvider
+import androidx.camera.testing.fakes.FakeLifecycleOwner
+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.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
+
+@LargeTest
+@RunWith(Parameterized::class)
+@SdkSuppress(minSdkVersion = 21)
+class BindUnbindUseCasesStressTest(
+    private val cameraId: String,
+    private val extensionMode: Int
+) {
+    @get:Rule
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
+
+    @get:Rule
+    val repeatRule = RepeatRule()
+
+    private val context = ApplicationProvider.getApplicationContext<Context>()
+
+    private lateinit var cameraProvider: ProcessCameraProvider
+    private lateinit var extensionsManager: ExtensionsManager
+    private lateinit var camera: Camera
+    private lateinit var baseCameraSelector: CameraSelector
+    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())
+        }
+        cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
+        extensionsManager = ExtensionsManager.getInstanceAsync(
+            context,
+            cameraProvider
+        )[10000, TimeUnit.MILLISECONDS]
+
+        baseCameraSelector = CameraSelectorUtil.createCameraSelectorById(cameraId)
+        assumeTrue(extensionsManager.isExtensionAvailable(baseCameraSelector, extensionMode))
+
+        extensionCameraSelector = extensionsManager.getExtensionEnabledCameraSelector(
+            baseCameraSelector,
+            extensionMode
+        )
+
+        camera = withContext(Dispatchers.Main) {
+            lifecycleOwner = FakeLifecycleOwner()
+            lifecycleOwner.startAndResume()
+            cameraProvider.bindToLifecycle(lifecycleOwner, extensionCameraSelector)
+        }
+
+        preview = Preview.Builder().build()
+        imageCapture = ImageCapture.Builder().build()
+        imageAnalysis = ImageAnalysis.Builder().build()
+
+        isImageAnalysisSupported =
+            camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis)
+    }
+
+    @After
+    fun cleanUp(): Unit = runBlocking {
+        if (::cameraProvider.isInitialized) {
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+                cameraProvider.shutdown()[10000, TimeUnit.MILLISECONDS]
+            }
+        }
+
+        if (::extensionsManager.isInitialized) {
+            extensionsManager.shutdown()[10000, TimeUnit.MILLISECONDS]
+        }
+    }
+
+    companion object {
+        @JvmStatic
+        @get:Parameterized.Parameters(name = "cameraId = {0}, extensionMode = {1}")
+        val parameters: Collection<Array<Any>>
+            get() = ExtensionsTestUtil.getAllCameraIdModeCombinations()
+    }
+
+    @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
+
+            withContext(Dispatchers.Main) {
+                preview.setSurfaceProvider(
+                    SurfaceTextureProvider.createSurfaceTextureProvider(
+                        previewFrameAvailableMonitor.createSurfaceTextureCallback()
+                    )
+                )
+
+                if (isImageAnalysisSupported) {
+                    analyzerFrameAvailableMonitor = ImageAnalysisImageAvailableMonitor()
+                    imageAnalysis.setAnalyzer(
+                        Executors.newSingleThreadExecutor(),
+                        analyzerFrameAvailableMonitor!!.createAnalyzer()
+                    )
+
+                    cameraProvider.bindToLifecycle(
+                        lifecycleOwner,
+                        extensionCameraSelector,
+                        preview,
+                        imageCapture,
+                        imageAnalysis
+                    )
+                } else {
+                    cameraProvider.bindToLifecycle(
+                        lifecycleOwner,
+                        extensionCameraSelector,
+                        preview,
+                        imageCapture
+                    )
+                }
+            }
+
+            previewFrameAvailableMonitor.awaitSurfaceTextureReadyAndAssert()
+            previewFrameAvailableMonitor.awaitAvailableFramesAndAssert()
+
+            imageCapture.takePicture(
+                Executors.newSingleThreadExecutor(),
+                imageCaptureCaptureSuccessMonitor.createCaptureCallback()
+            )
+
+            imageCaptureCaptureSuccessMonitor.awaitCaptureSuccessAndAssert()
+
+            analyzerFrameAvailableMonitor?.awaitAvailableFramesAndAssert()
+
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+            }
+        }
+    }
+
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun canCaptureImage_afterBindUnbindUseCasesTenTimes(): Unit = runBlocking {
+        lateinit var previewFrameAvailableMonitor: PreviewFrameAvailableMonitor
+        lateinit var imageCaptureCaptureSuccessMonitor: ImageCaptureCaptureSuccessMonitor
+        var analyzerFrameAvailableMonitor: ImageAnalysisImageAvailableMonitor? = null
+
+        for (i in 1..STRESS_TEST_OPERATION_REPEAT_COUNT) {
+            previewFrameAvailableMonitor = PreviewFrameAvailableMonitor()
+            imageCaptureCaptureSuccessMonitor = ImageCaptureCaptureSuccessMonitor()
+
+            withContext(Dispatchers.Main) {
+                preview.setSurfaceProvider(
+                    SurfaceTextureProvider.createSurfaceTextureProvider(
+                        previewFrameAvailableMonitor.createSurfaceTextureCallback()
+                    )
+                )
+
+                if (isImageAnalysisSupported) {
+                    analyzerFrameAvailableMonitor = ImageAnalysisImageAvailableMonitor()
+                    imageAnalysis.setAnalyzer(
+                        Executors.newSingleThreadExecutor(),
+                        analyzerFrameAvailableMonitor!!.createAnalyzer()
+                    )
+
+                    cameraProvider.bindToLifecycle(
+                        lifecycleOwner,
+                        extensionCameraSelector,
+                        preview,
+                        imageCapture,
+                        imageAnalysis
+                    )
+                } else {
+                    cameraProvider.bindToLifecycle(
+                        lifecycleOwner,
+                        extensionCameraSelector,
+                        preview,
+                        imageCapture
+                    )
+                }
+            }
+
+            withContext(Dispatchers.Main) {
+                if (i != STRESS_TEST_OPERATION_REPEAT_COUNT) {
+                    cameraProvider.unbindAll()
+                }
+            }
+        }
+
+        previewFrameAvailableMonitor.awaitSurfaceTextureReadyAndAssert()
+        previewFrameAvailableMonitor.awaitAvailableFramesAndAssert()
+
+        imageCapture.takePicture(
+            Executors.newSingleThreadExecutor(),
+            imageCaptureCaptureSuccessMonitor.createCaptureCallback()
+        )
+
+        imageCaptureCaptureSuccessMonitor.awaitCaptureSuccessAndAssert()
+
+        analyzerFrameAvailableMonitor?.awaitAvailableFramesAndAssert()
+    }
+
+    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 {
+                if (complete) {
+                    return@runBlocking
+                }
+
+                withContext(Dispatchers.Main) {
+                    synchronized(isSurfaceTextureReleasedLock) {
+                        if (!isSurfaceTextureReleased) {
+                            surfaceTexture.updateTexImage()
+                        }
+                    }
+                }
+
+                previewFrameCountDownLatch?.let {
+                    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
+                ) {
+                    surfaceTexture.attachToGLContext(GLUtil.getTexIdFromGLContext())
+                    surfaceTexture.setOnFrameAvailableListener(
+                        onFrameAvailableListener,
+                        frameAvailableHandler
+                    )
+
+                    surfaceTextureLatch.countDown()
+                }
+
+                override fun onSafeToRelease(surfaceTexture: SurfaceTexture) {
+                    synchronized(isSurfaceTextureReleasedLock) {
+                        isSurfaceTextureReleased = true
+                        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/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCameraStressTest.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCameraStressTest.kt
new file mode 100644
index 0000000..ce9d1e6
--- /dev/null
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCameraStressTest.kt
@@ -0,0 +1,190 @@
+/*
+ * 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.camera.integration.extensions
+
+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.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
+import androidx.camera.integration.extensions.util.ExtensionsTestUtil.STRESS_TEST_REPEAT_COUNT
+import androidx.camera.integration.extensions.utils.CameraSelectorUtil
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
+import androidx.camera.testing.SurfaceTextureProvider
+import androidx.camera.testing.fakes.FakeLifecycleOwner
+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,
+    private val extensionMode: Int
+) {
+    @get:Rule
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
+
+    @get:Rule
+    val repeatRule = RepeatRule()
+
+    private val context = ApplicationProvider.getApplicationContext<Context>()
+
+    private lateinit var cameraProvider: ProcessCameraProvider
+    private lateinit var extensionsManager: ExtensionsManager
+    private lateinit var camera: Camera
+    private lateinit var baseCameraSelector: CameraSelector
+    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())
+        }
+        cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
+        extensionsManager = ExtensionsManager.getInstanceAsync(
+            context,
+            cameraProvider
+        )[10000, TimeUnit.MILLISECONDS]
+
+        baseCameraSelector = CameraSelectorUtil.createCameraSelectorById(cameraId)
+        assumeTrue(extensionsManager.isExtensionAvailable(baseCameraSelector, extensionMode))
+
+        extensionCameraSelector = extensionsManager.getExtensionEnabledCameraSelector(
+            baseCameraSelector,
+            extensionMode
+        )
+
+        camera = withContext(Dispatchers.Main) {
+            lifecycleOwner = FakeLifecycleOwner()
+            lifecycleOwner.startAndResume()
+            cameraProvider.bindToLifecycle(lifecycleOwner, extensionCameraSelector)
+        }
+
+        preview = Preview.Builder().build()
+        withContext(Dispatchers.Main) {
+            preview.setSurfaceProvider(SurfaceTextureProvider.createSurfaceTextureProvider())
+        }
+        imageCapture = ImageCapture.Builder().build()
+        imageAnalysis = ImageAnalysis.Builder().build()
+
+        isImageAnalysisSupported =
+            camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis)
+    }
+
+    @After
+    fun cleanUp(): Unit = runBlocking {
+        if (::cameraProvider.isInitialized) {
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+                cameraProvider.shutdown()[10000, TimeUnit.MILLISECONDS]
+            }
+        }
+
+        if (::extensionsManager.isInitialized) {
+            extensionsManager.shutdown()[10000, TimeUnit.MILLISECONDS]
+        }
+    }
+
+    companion object {
+        @JvmStatic
+        @get:Parameterized.Parameters(name = "cameraId = {0}, extensionMode = {1}")
+        val parameters: Collection<Array<Any>>
+            get() = ExtensionsTestUtil.getAllCameraIdModeCombinations()
+    }
+
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCameraStressTest(): Unit = runBlocking {
+        for (i in 1..STRESS_TEST_OPERATION_REPEAT_COUNT) {
+            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) {
+                camera.cameraInfo.cameraState.observe(lifecycleOwner, observer)
+
+                if (isImageAnalysisSupported) {
+                    cameraProvider.bindToLifecycle(
+                        lifecycleOwner,
+                        extensionCameraSelector,
+                        preview,
+                        imageCapture,
+                        imageAnalysis
+                    )
+                } else {
+                    cameraProvider.bindToLifecycle(
+                        lifecycleOwner,
+                        extensionCameraSelector,
+                        preview,
+                        imageCapture
+                    )
+                }
+            }
+
+            assertThat(openCameraLatch.await(3000, TimeUnit.MILLISECONDS)).isTrue()
+
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+            }
+
+            assertThat(closeCameraLatch.await(3000, TimeUnit.MILLISECONDS)).isTrue()
+
+            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
new file mode 100644
index 0000000..9f5795f
--- /dev/null
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/OpenCloseCaptureSessionStressTest.kt
@@ -0,0 +1,425 @@
+/*
+ * 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.camera.integration.extensions
+
+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.camera2.interop.Camera2CameraInfo
+import androidx.camera.core.Camera
+import androidx.camera.core.CameraFilter
+import androidx.camera.core.CameraInfo
+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.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
+import androidx.camera.core.impl.Identifier
+import androidx.camera.core.impl.MutableOptionsBundle
+import androidx.camera.core.impl.OptionsBundle
+import androidx.camera.core.impl.UseCaseConfigFactory
+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
+import androidx.camera.integration.extensions.util.ExtensionsTestUtil.STRESS_TEST_REPEAT_COUNT
+import androidx.camera.integration.extensions.utils.CameraSelectorUtil
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.testing.CameraUtil
+import androidx.camera.testing.CameraUtil.PreTestCameraIdList
+import androidx.camera.testing.SurfaceTextureProvider
+import androidx.camera.testing.fakes.FakeLifecycleOwner
+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,
+    private val extensionMode: Int
+) {
+    @get:Rule
+    val useCamera = CameraUtil.grantCameraPermissionAndPreTest(
+        PreTestCameraIdList(Camera2Config.defaultConfig())
+    )
+
+    @get:Rule
+    val repeatRule = RepeatRule()
+
+    private val context = ApplicationProvider.getApplicationContext<Context>()
+
+    private lateinit var cameraProvider: ProcessCameraProvider
+    private lateinit var extensionsManager: ExtensionsManager
+    private lateinit var camera: Camera
+    private lateinit var baseCameraSelector: CameraSelector
+    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
+    private val cameraEventMonitor = CameraEventMonitor()
+
+    @Before
+    fun setUp(): Unit = runBlocking {
+        if (extensionMode != ExtensionMode.NONE) {
+            assumeTrue(ExtensionsTestUtil.isTargetDeviceAvailableForExtensions())
+        }
+        cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS]
+        extensionsManager = ExtensionsManager.getInstanceAsync(
+            context,
+            cameraProvider
+        )[10000, TimeUnit.MILLISECONDS]
+
+        baseCameraSelector = CameraSelectorUtil.createCameraSelectorById(cameraId)
+        assumeTrue(extensionsManager.isExtensionAvailable(baseCameraSelector, extensionMode))
+
+        extensionCameraSelector = extensionsManager.getExtensionEnabledCameraSelector(
+            baseCameraSelector,
+            extensionMode
+        )
+
+        camera = withContext(Dispatchers.Main) {
+            lifecycleOwner = FakeLifecycleOwner()
+            lifecycleOwner.startAndResume()
+            cameraProvider.bindToLifecycle(lifecycleOwner, extensionCameraSelector)
+        }
+
+        preview = Preview.Builder().build()
+        withContext(Dispatchers.Main) {
+            preview.setSurfaceProvider(SurfaceTextureProvider.createSurfaceTextureProvider())
+        }
+        imageCapture = ImageCapture.Builder().build()
+        imageAnalysis = ImageAnalysis.Builder().build()
+
+        isImageAnalysisSupported =
+            camera.isUseCasesCombinationSupported(preview, imageCapture, imageAnalysis)
+    }
+
+    @After
+    fun cleanUp(): Unit = runBlocking {
+        if (::cameraProvider.isInitialized) {
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+                cameraProvider.shutdown()[10000, TimeUnit.MILLISECONDS]
+            }
+        }
+
+        if (::extensionsManager.isInitialized) {
+            extensionsManager.shutdown()[10000, TimeUnit.MILLISECONDS]
+        }
+    }
+
+    @Test
+    @RepeatRule.Repeat(times = STRESS_TEST_REPEAT_COUNT)
+    fun openCloseCaptureSessionStressTest(): Unit = runBlocking {
+        for (i in 1..STRESS_TEST_OPERATION_REPEAT_COUNT) {
+            cameraEventMonitor.reset()
+
+            withContext(Dispatchers.Main) {
+                // Retrieves the camera selector which allows to monitor camera event callbacks
+                val extensionEnabledCameraEventMonitorCameraSelector =
+                    getExtensionsCameraEventMonitorCameraSelector(
+                        extensionsManager,
+                        extensionMode,
+                        baseCameraSelector
+                    )
+
+                if (isImageAnalysisSupported) {
+                    cameraProvider.bindToLifecycle(
+                        lifecycleOwner,
+                        extensionEnabledCameraEventMonitorCameraSelector,
+                        preview,
+                        imageCapture,
+                        imageAnalysis
+                    )
+                } else {
+                    cameraProvider.bindToLifecycle(
+                        lifecycleOwner,
+                        extensionEnabledCameraEventMonitorCameraSelector,
+                        preview,
+                        imageCapture
+                    )
+                }
+            }
+
+            cameraEventMonitor.awaitSessionEnabledAndAssert()
+
+            withContext(Dispatchers.Main) {
+                cameraProvider.unbindAll()
+            }
+
+            cameraEventMonitor.awaitSessionDisabledAndAssert()
+        }
+    }
+
+    companion object {
+        @JvmStatic
+        @get:Parameterized.Parameters(name = "cameraId = {0}, extensionMode = {1}")
+        val parameters: Collection<Array<Any>>
+            get() = ExtensionsTestUtil.getAllCameraIdModeCombinations()
+
+        /**
+         * Retrieves the default extended camera config provider id string
+         */
+        private fun getExtendedCameraConfigProviderId(@ExtensionMode.Mode mode: Int): String =
+            when (mode) {
+                ExtensionMode.BOKEH -> "EXTENSION_MODE_BOKEH"
+                ExtensionMode.HDR -> "EXTENSION_MODE_HDR"
+                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"
+            }
+
+        /**
+         * Retrieves the camera event monitor extended camera config provider id string
+         */
+        private fun getCameraEventMonitorCameraConfigProviderId(
+            @ExtensionMode.Mode mode: Int
+        ): String = "${getExtendedCameraConfigProviderId(mode)}-camera-event-monitor"
+    }
+
+    /**
+     * Gets the camera selector which allows to monitor the camera event callbacks
+     */
+    private fun getExtensionsCameraEventMonitorCameraSelector(
+        extensionsManager: ExtensionsManager,
+        extensionMode: Int,
+        baseCameraSelector: CameraSelector
+    ): CameraSelector {
+        // Injects the ExtensionsCameraEventMonitorUseCaseConfigFactory which allows to monitor and
+        // verify the camera event callbacks
+        injectExtensionsCameraEventMonitorUseCaseConfigFactory(
+            extensionsManager,
+            extensionMode,
+            baseCameraSelector
+        )
+
+        val builder = CameraSelector.Builder.fromSelector(baseCameraSelector)
+        // Add an ExtensionCameraEventMonitorCameraFilter which includes the CameraFilter to check
+        // whether the camera is supported for the extension mode or not and also includes the
+        // identifier to find the extended camera config provider from
+        // ExtendedCameraConfigProviderStore
+        builder.addCameraFilter(
+            ExtensionsCameraEventMonitorCameraFilter(
+                extensionsManager,
+                extensionMode
+            )
+        )
+        return builder.build()
+    }
+
+    /**
+     * Injects the ExtensionsCameraEventMonitorUseCaseConfigFactory which allows to monitor and
+     * verify the camera event callbacks
+     */
+    private fun injectExtensionsCameraEventMonitorUseCaseConfigFactory(
+        extensionsManager: ExtensionsManager,
+        extensionMode: Int,
+        baseCameraSelector: CameraSelector
+    ): Unit = runBlocking {
+        val defaultConfigProviderId =
+            Identifier.create(getExtendedCameraConfigProviderId(extensionMode))
+        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()
+            }
+        }
+
+        // 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.
+        ExtendedCameraConfigProviderStore.addConfig(cameraEventConfigProviderId) {
+                cameraInfo: CameraInfo, context: Context ->
+            // Retrieves the default extended camera config provider and
+            // ExtensionsUseCaseConfigFactory
+            val defaultCameraConfigProvider =
+                ExtendedCameraConfigProviderStore.getConfigProvider(defaultConfigProviderId)
+            val defaultCameraConfig = defaultCameraConfigProvider.getConfig(cameraInfo, context)!!
+            val defaultExtensionsUseCaseConfigFactory =
+                defaultCameraConfig.retrieveOption(CameraConfig.OPTION_USECASE_CONFIG_FACTORY, null)
+
+            // Creates a new ExtensionsCameraEventMonitorUseCaseConfigFactory on top of the default
+            // ExtensionsCameraEventMonitorUseCaseConfigFactory to monitor the capture session
+            // callbacks
+            val extensionsCameraEventMonitorUseCaseConfigFactory =
+                ExtensionsCameraEventMonitorUseCaseConfigFactory(
+                    defaultExtensionsUseCaseConfigFactory,
+                    cameraEventMonitor
+                )
+
+            // Creates the config from the original config and replaces its use case config factory
+            // with the ExtensionsCameraEventMonitorUseCaseConfigFactory
+            val mutableOptionsBundle = MutableOptionsBundle.from(defaultCameraConfig)
+            mutableOptionsBundle.insertOption(
+                CameraConfig.OPTION_USECASE_CONFIG_FACTORY,
+                extensionsCameraEventMonitorUseCaseConfigFactory
+            )
+
+            // Returns a CameraConfig implemented with the updated config
+            object : CameraConfig {
+                val config = OptionsBundle.from(mutableOptionsBundle)
+
+                override fun getConfig(): Config {
+                    return config
+                }
+
+                override fun getCompatibilityId(): Identifier {
+                    return config.retrieveOption(CameraConfig.OPTION_COMPATIBILITY_ID)!!
+                }
+            }
+        }
+    }
+
+    /**
+     * A ExtensionsCameraEventMonitorCameraFilter which includes the CameraFilter to check whether
+     * the camera is supported for the extension mode or not and also includes the identifier to
+     * find the extended camera config provider from ExtendedCameraConfigProviderStore.
+     */
+    private class ExtensionsCameraEventMonitorCameraFilter constructor(
+        private val extensionManager: ExtensionsManager,
+        @ExtensionMode.Mode private val mode: Int
+    ) : CameraFilter {
+        override fun getIdentifier(): Identifier {
+            return Identifier.create(getCameraEventMonitorCameraConfigProviderId(mode))
+        }
+
+        override fun filter(cameraInfos: MutableList<CameraInfo>): MutableList<CameraInfo> =
+            cameraInfos.mapNotNull { cameraInfo ->
+                val cameraId = Camera2CameraInfo.from(cameraInfo).cameraId
+                val cameraIdCameraSelector = CameraSelectorUtil.createCameraSelectorById(cameraId)
+                if (extensionManager.isExtensionAvailable(cameraIdCameraSelector, mode)) {
+                    cameraInfo
+                } else {
+                    null
+                }
+            }.toMutableList()
+    }
+
+    /**
+     * A UseCaseConfigFactory implemented on top of the default ExtensionsUseCaseConfigFactory to
+     * monitor the camera event callbacks
+     */
+    private class ExtensionsCameraEventMonitorUseCaseConfigFactory constructor(
+        private val useCaseConfigFactory: UseCaseConfigFactory?,
+        private val cameraEventMonitor: CameraEventMonitor
+    ) :
+        UseCaseConfigFactory {
+        override fun getConfig(
+            captureType: UseCaseConfigFactory.CaptureType,
+            captureMode: Int
+        ): Config {
+            // Retrieves the config from the default ExtensionsUseCaseConfigFactory
+            val mutableOptionsBundle = useCaseConfigFactory?.getConfig(
+                captureType, captureMode)?.let {
+                MutableOptionsBundle.from(it)
+            } ?: MutableOptionsBundle.create()
+
+            // Adds the CameraEventMonitor to the original CameraEventCallbacks of ImageCapture to
+            // monitor the camera event callbacks
+            if (captureType.equals(UseCaseConfigFactory.CaptureType.IMAGE_CAPTURE)) {
+                var cameraEventCallbacks = mutableOptionsBundle.retrieveOption(
+                    Camera2ImplConfig.CAMERA_EVENT_CALLBACK_OPTION,
+                    null
+                )
+
+                if (cameraEventCallbacks != null) {
+                    cameraEventCallbacks.addAll(
+                        mutableListOf<CameraEventCallback>(
+                            cameraEventMonitor
+                        )
+                    )
+                } else {
+                    cameraEventCallbacks = CameraEventCallbacks(cameraEventMonitor)
+                }
+
+                mutableOptionsBundle.insertOption(
+                    Camera2ImplConfig.CAMERA_EVENT_CALLBACK_OPTION,
+                    cameraEventCallbacks
+                )
+            }
+
+            return OptionsBundle.from(mutableOptionsBundle)
+        }
+    }
+
+    /**
+     * 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 super.onEnableSession()
+        }
+
+        override fun onDisableSession(): CaptureConfig? {
+            sessionDisabledLatch.countDown()
+            return super.onDisableSession()
+        }
+
+        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/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/util/ExtensionsTestUtil.kt b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/util/ExtensionsTestUtil.kt
index 950f4fe..6cc82b4 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/util/ExtensionsTestUtil.kt
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/util/ExtensionsTestUtil.kt
@@ -52,6 +52,23 @@
         }
 
     /**
+     * Gets a list of all camera id and mode combinations. Normal mode and all extension modes will
+     * be included.
+     */
+    @JvmStatic
+    fun getAllCameraIdModeCombinations(): List<Array<Any>> =
+        arrayListOf<Array<Any>>().apply {
+            val allModes = mutableListOf<Int>()
+            allModes.add(0, ExtensionMode.NONE)
+            allModes.addAll(ExtensionModeUtil.AVAILABLE_EXTENSION_MODES)
+            CameraUtil.getBackwardCompatibleCameraIdListOrThrow().forEach { cameraId ->
+                allModes.forEach { mode ->
+                    add(arrayOf(cameraId, mode))
+                }
+            }
+        }
+
+    /**
      * Creates an [ImageCaptureExtenderImpl] object for specific [ExtensionMode] and
      * camera id.
      *
@@ -113,4 +130,25 @@
         // extensions and it will cause pre-submit failures.
         return !Build.MODEL.contains("Cuttlefish", true)
     }
+
+    /**
+     * 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/car/app/app/api/OWNERS b/car/app/API_OWNERS
similarity index 90%
rename from car/app/app/api/OWNERS
rename to car/app/API_OWNERS
index 8fffa15..ce7ee14 100644
--- a/car/app/app/api/OWNERS
+++ b/car/app/API_OWNERS
@@ -11,4 +11,3 @@
 [email protected]
 [email protected]
 [email protected]
[email protected]
\ No newline at end of file
diff --git a/car/app/OWNERS b/car/app/OWNERS
index 4964102..040e49d 100644
--- a/car/app/OWNERS
+++ b/car/app/OWNERS
@@ -1,6 +1,11 @@
 # Bug component: 460472
[email protected]
[email protected]
[email protected] #{LAST_RESORT_SUGGESTION}
[email protected] #{LAST_RESORT_SUGGESTION}
 
-# back up
[email protected]
\ No newline at end of file
+# API ownership
+per-file app/api/*=file:/car/app/API_OWNERS
+per-file app-automotive/api/*=file:/car/app/API_OWNERS
+per-file app-projected/api/*=file:/car/app/API_OWNERS
+per-file app-testing/api/*=file:/car/app/API_OWNERS
+
+# Feature owners
diff --git a/car/app/app-automotive/api/OWNERS b/car/app/app-automotive/api/OWNERS
deleted file mode 100644
index 816ecbd..0000000
--- a/car/app/app-automotive/api/OWNERS
+++ /dev/null
@@ -1,15 +0,0 @@
-set noparent
-
[email protected]
[email protected]
[email protected]
-
-# back up
[email protected]
-
-# core team
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
\ No newline at end of file
diff --git a/car/app/app-projected/api/OWNERS b/car/app/app-projected/api/OWNERS
deleted file mode 100644
index ab91e1e..0000000
--- a/car/app/app-projected/api/OWNERS
+++ /dev/null
@@ -1,12 +0,0 @@
-set noparent
-
[email protected]
[email protected]
[email protected]
-
-# core team
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
\ No newline at end of file
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java
index 333f99a..34c1e31 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/common/SamplePlaces.java
@@ -159,7 +159,7 @@
         Location location5 = new Location(SamplePlaces.class.getSimpleName());
         location5.setLatitude(37.422014);
         location5.setLongitude(-122.084776);
-        SpannableString title5 = new SpannableString(" ");
+        SpannableString title5 = new SpannableString("  Googleplex");
         title5.setSpan(CarIconSpan.create(new CarIcon.Builder(
                         IconCompat.createWithBitmap(
                                 BitmapFactory.decodeResource(
diff --git a/car/app/app-testing/api/OWNERS b/car/app/app-testing/api/OWNERS
deleted file mode 100644
index f067310..0000000
--- a/car/app/app-testing/api/OWNERS
+++ /dev/null
@@ -1,11 +0,0 @@
-set noparent
-
[email protected]
[email protected]
-
-# core team
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
\ No newline at end of file
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 2287956..c515408 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
@@ -28,73 +28,70 @@
 
 import java.lang.annotation.Retention;
 
-/**
- * Contains information about a {@link Session}.
- */
+/** Information about a {@link Session}, such as the physical display and the session ID. */
 @RequiresCarApi(5)
 @CarProtocol
 public class SessionInfo {
-    /**
-     * The main infotainment display.
-     */
+    /** The primary infotainment display usually in the center column of the vehicle. */
     public static final int DISPLAY_TYPE_MAIN = 0;
-    /**
-     * Cluster display, usually located behind the steering wheel.
-     */
+
+    /** The cluster display, usually located behind the steering wheel.  */
     public static final int DISPLAY_TYPE_CLUSTER = 1;
 
     /**
-     * Defines which kind of {@link androidx.car.app.model.Template}s {@link Screen}s from this
-     * {@link Session} can return for the given display it will render on.
-     *
      * @hide
      */
-
     @IntDef({DISPLAY_TYPE_MAIN, DISPLAY_TYPE_CLUSTER})
     @Retention(SOURCE)
     public @interface DisplayType {
     }
 
     /**
-     * A default {@link SessionInfo} for the main display.
+     * A default {@link SessionInfo} for the main display, used when the host is on a version
+     * that doesn't support this new class.
      *
      * @hide
      */
-    public static final SessionInfo DEFAULT_SESSION_INFO = new SessionInfo(
+    @RestrictTo(LIBRARY)
+    static final SessionInfo DEFAULT_SESSION_INFO = new SessionInfo(
             DISPLAY_TYPE_MAIN, "main");
+
+    /** A string identifier unique per physical display. */
     @Keep
     @NonNull
     private final String mSessionId;
+
+    /** The type of display the {@link Session} is rendering on. */
     @Keep
     @DisplayType
     private final int mDisplayType;
 
     /**
-     * Returns the {@code id} for the {@link Session}.
+     * Returns a session-stable ID, unique to the display that the {@link Session} is rendering on.
      */
     @NonNull
     public String getSessionId() {
         return mSessionId;
     }
 
-    /**
-     * Returns the {@code id} for the displayType.
-     */
+    /** Returns the type of display that the {@link Session} is rendering on. */
+    @DisplayType
     public int getDisplayType() {
         return mDisplayType;
     }
 
     /**
-     * Creates a new {@link SessionInfo} with the provided {@code displayType} and {@code sessionId}
+     * Creates a new {@link SessionInfo} with the provided {@code displayType} and {@code
+     * sessionId}.
      */
     public SessionInfo(@DisplayType int displayType, @NonNull String sessionId) {
         mDisplayType = displayType;
         mSessionId = sessionId;
     }
 
+    // Required for Bundler
     private SessionInfo() {
         mSessionId = "main";
         mDisplayType = DISPLAY_TYPE_MAIN;
     }
-
 }
diff --git a/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java
index 264ee00..6b5d0ad 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java
@@ -160,8 +160,8 @@
          *
          * <p>Unless set with this method, the template will not have a title.
          *
-         * <p>Only {@link DistanceSpan}s and {@link DurationSpan}s are supported in the input
-         * string.
+         * <p>Only {@link DistanceSpan}s, {@link DurationSpan}s and {@link CarIconSpan} are
+         * supported in the input string.
          *
          * @throws NullPointerException     if {@code title} is {@code null}
          * @throws IllegalArgumentException if {@code title} contains unsupported spans
@@ -170,7 +170,7 @@
         @NonNull
         public Builder setTitle(@NonNull CharSequence title) {
             mTitle = CarText.create(requireNonNull(title));
-            CarTextConstraints.TEXT_ONLY.validateOrThrow(mTitle);
+            CarTextConstraints.TEXT_AND_ICON.validateOrThrow(mTitle);
             return this;
         }
 
@@ -237,7 +237,6 @@
          * set on the template, the header is hidden.
          *
          * @throws IllegalArgumentException if the {@link Pane} does not meet the requirements
-         *
          * @see androidx.car.app.constraints.ConstraintManager#getContentLimit(int)
          */
         @NonNull
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
new file mode 100644
index 0000000..34d77c0
--- /dev/null
+++ b/car/app/app/src/test/java/androidx/car/app/SessionInfoTest.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.car.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class SessionInfoTest {
+    private static final String TEST_SESSION_ID = "test session id";
+
+    @Test
+    public void dataClassTest() {
+        SessionInfo result = new SessionInfo(SessionInfo.DISPLAY_TYPE_MAIN, TEST_SESSION_ID);
+
+        assertThat(result.getSessionId()).isEqualTo(TEST_SESSION_ID);
+        assertThat(result.getDisplayType()).isEqualTo(SessionInfo.DISPLAY_TYPE_MAIN);
+    }
+}
diff --git a/car/app/app/src/test/java/androidx/car/app/model/PaneTemplateTest.java b/car/app/app/src/test/java/androidx/car/app/model/PaneTemplateTest.java
index e52c422..1f07561 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/PaneTemplateTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/PaneTemplateTest.java
@@ -46,6 +46,29 @@
     }
 
     @Test
+    public void paneTemplate_title_unsupportedSpans_throws() {
+        CharSequence title1 = TestUtils.getCharSequenceWithClickableSpan("Title");
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> new PaneTemplate.Builder(TestUtils.createPane(2, 2)).setTitle(
+                        title1).build());
+
+        CharSequence title2 = TestUtils.getCharSequenceWithColorSpan("Title");
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> new PaneTemplate.Builder(TestUtils.createPane(2, 2)).setTitle(
+                        title2).build());
+
+        // CarIconSpan assert no exceptions
+        CharSequence title3 = TestUtils.getCharSequenceWithIconSpan("Title");
+        new PaneTemplate.Builder(TestUtils.createPane(2, 2)).setTitle(title3).build();
+
+        // DistanceSpan and DurationSpan assert no exceptions
+        CharSequence title4 = TestUtils.getCharSequenceWithDistanceAndDurationSpans("Title");
+        new PaneTemplate.Builder(TestUtils.createPane(2, 2)).setTitle(title4).build();
+    }
+
+    @Test
     public void pane_action_unsupportedSpans_throws() {
         CharSequence title1 = TestUtils.getCharSequenceWithClickableSpan("Title");
         Action action1 = new Action.Builder().setTitle(title1).build();
@@ -97,8 +120,9 @@
     @Test
     public void pane_moreThanMaxPrimaryButtons_throws() {
         Action primaryAction = new Action.Builder().setTitle("primaryAction")
-                                       .setOnClickListener(() -> {})
-                                       .setFlags(FLAG_PRIMARY).build();
+                .setOnClickListener(() -> {
+                })
+                .setFlags(FLAG_PRIMARY).build();
         Row rowMeetingMaxTexts =
                 new Row.Builder().setTitle("Title").addText("text1").addText("text2").build();
 
@@ -112,8 +136,8 @@
         assertThrows(
                 IllegalArgumentException.class,
                 () -> new PaneTemplate.Builder(paneExceedsMaxPrimaryAction)
-                              .setTitle("Title")
-                              .build());
+                        .setTitle("Title")
+                        .build());
     }
 
     @Test
diff --git a/collection/collection/build.gradle b/collection/collection/build.gradle
index b6487f2..30d7483 100644
--- a/collection/collection/build.gradle
+++ b/collection/collection/build.gradle
@@ -129,6 +129,7 @@
         android = Publish.NONE
         jvm = Publish.SNAPSHOT_AND_RELEASE
         linux = Publish.SNAPSHOT_AND_RELEASE
+        mac = Publish.SNAPSHOT_AND_RELEASE
     }
     mavenGroup = LibraryGroups.COLLECTION
     inceptionYear = "2018"
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ClassStabilityTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ClassStabilityTransformTests.kt
index 9b642d7..75bc2ff 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ClassStabilityTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ClassStabilityTransformTests.kt
@@ -726,9 +726,6 @@
         """
             @Composable
             fun A(y: Any?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)<A()>,<A(Empt...>,<A(Sing...>,<A(Sing...>,<A(Sing...>,<A(Sing...>,<A(Sing...>,<A(Sing...>,<A(Doub...>,<A(Doub...>,<A(Doub...>,<A(Doub...>,<A(X(li...>,<A(X(li...>,<A(NonB...>,<A(NonB...>,<A(Stab...>,<A(Unst...>:Test.kt")
               val %dirty = %changed
@@ -764,9 +761,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(y, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -864,9 +858,6 @@
             }
             @Composable
             fun A(y: Any, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)<A(X(li...>,<A(Stab...>,<A(Unst...>:Test.kt")
               used(y)
@@ -876,9 +867,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(y, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -905,9 +893,6 @@
         """
             @Composable
             fun A(y: Any, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)<A(Wrap...>:Test.kt")
               used(y)
@@ -915,9 +900,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(y, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -950,9 +932,6 @@
         """
             @Composable
             fun <V> B(value: V, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B)<A(Wrap...>:Test.kt")
               val %dirty = %changed
@@ -967,16 +946,10 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 B(value, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             @ComposableInferredTarget(scheme = "[0[0]]")
             fun <T> X(items: List<T>, itemContent: Function3<T, Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(X)P(1)*<itemCo...>:Test.kt")
               val %dirty = %changed
@@ -988,24 +961,15 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 X(items, itemContent, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun C(items: List<String>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(C)<X(item...>:Test.kt")
               X(items, ComposableSingletons%TestKt.lambda-1, %composer, 0b00111000)
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 C(items, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function3<String, Composer, Int, Unit> = composableLambdaInstance(<>, false) { item: String, %composer: Composer?, %changed: Int ->
@@ -1064,9 +1028,6 @@
             }
             @Composable
             fun A(y: Int, x: Any, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)P(1)<B(x)>:Test.kt")
               used(y)
@@ -1074,24 +1035,15 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(y, x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun B(x: Any, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B):Test.kt")
               used(x)
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 B(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1117,9 +1069,6 @@
             }
             @Composable
             fun A(y: Int, x: Foo, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)P(1)<B(x)>:Test.kt")
               used(y)
@@ -1127,24 +1076,15 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(y, x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun B(x: Any, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B):Test.kt")
               used(x)
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 B(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt
index 56f521e..ba83110 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt
@@ -197,24 +197,15 @@
         """
             @Composable
             fun VarArgsFirst(foo: Array<out Any?>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(VarArgsFirst):Test.kt#2487m")
               println(foo)
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 VarArgsFirst(*foo, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun VarArgsCaller(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(VarArgsCaller)<VarArg...>:Test.kt#2487m")
               if (%changed !== 0 || !%composer.skipping) {
@@ -228,9 +219,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 VarArgsCaller(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -437,9 +425,6 @@
                 @Composable
                 @ComposableInferredTarget(scheme = "[0[0]]")
                 fun Wrapper(block: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-                  if (isTraceInProgress()) {
-                    traceEventStart(<>)
-                  }
                   %composer = %composer.startRestartGroup(<>)
                   sourceInformation(%composer, "C(Wrapper)<block(...>:Test.kt#2487m")
                   val %dirty = %changed
@@ -454,15 +439,9 @@
                   %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                     Wrapper(block, %composer, %changed or 0b0001)
                   }
-                  if (isTraceInProgress()) {
-                    traceEventEnd()
-                  }
                 }
                 @Composable
                 fun Leaf(text: String, %composer: Composer?, %changed: Int) {
-                  if (isTraceInProgress()) {
-                    traceEventStart(<>)
-                  }
                   %composer = %composer.startRestartGroup(<>)
                   sourceInformation(%composer, "C(Leaf):Test.kt#2487m")
                   val %dirty = %changed
@@ -477,15 +456,9 @@
                   %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                     Leaf(text, %composer, %changed or 0b0001)
                   }
-                  if (isTraceInProgress()) {
-                    traceEventEnd()
-                  }
                 }
                 @Composable
                 fun Test(value: Int, %composer: Composer?, %changed: Int) {
-                  if (isTraceInProgress()) {
-                    traceEventStart(<>)
-                  }
                   %composer = %composer.startRestartGroup(<>)
                   sourceInformation(%composer, "C(Test):Test.kt#2487m")
                   val %dirty = %changed
@@ -510,9 +483,6 @@
                   %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                     Test(value, %composer, %changed or 0b0001)
                   }
-                  if (isTraceInProgress()) {
-                    traceEventEnd()
-                  }
                 }
             """,
             validator = { element ->
@@ -578,9 +548,6 @@
                 @Composable
                 @ComposableInferredTarget(scheme = "[0[0]]")
                 fun composeVector(composable: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-                  if (isTraceInProgress()) {
-                    traceEventStart(<>)
-                  }
                   %composer = %composer.startRestartGroup(<>)
                   sourceInformation(%composer, "C(composeVector)<emit>:Test.kt#2487m")
                   val %dirty = %changed
@@ -613,9 +580,6 @@
                   %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                     composeVector(composable, %composer, %changed or 0b0001)
                   }
-                  if (isTraceInProgress()) {
-                    traceEventEnd()
-                  }
                 }
                 @Composable
                 @ComposableInferredTarget(scheme = "[0[0]]")
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ContextReceiversTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ContextReceiversTransformTests.kt
index 34ffefbe..e44b17b 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ContextReceiversTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ContextReceiversTransformTests.kt
@@ -58,9 +58,6 @@
         """
             @Composable
             fun Test(%this%: Foo, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -70,9 +67,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%this%, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -96,9 +90,6 @@
         """
             @Composable
             fun A(%this%: Foo, %this%: Bar, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -108,15 +99,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(%this%, %this%, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun B(%this%: Foo, %this%: Bar, %this%: FooBar, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -126,9 +111,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 B(%this%, %this%, %this%, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -152,9 +134,6 @@
         """
             @Composable
             fun String.A(%this%: Foo, %this%: Bar, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -164,15 +143,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(%this%, %this%, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun String.B(%this%: Foo, %this%: Bar, %this%: FooBar, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -182,9 +155,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 B(%this%, %this%, %this%, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -212,9 +182,6 @@
         """
             @Composable
             fun A(%this%: Foo, %this%: Bar, a: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -227,15 +194,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(%this%, %this%, a, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun B(%this%: Foo, %this%: Bar, %this%: FooBar, a: Int, b: String?, c: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -251,15 +212,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 B(%this%, %this%, %this%, a, b, c, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun C(%this%: Foo, a: Int, bar: Bar?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(C):Test.kt")
               val %dirty = %changed
@@ -283,9 +238,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 C(%this%, a, bar, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -305,9 +257,6 @@
         """
         @Composable
         fun String.B(%this%: Foo, %this%: Bar, %this%: FooBar, a: Int, b: String?, c: Int, %composer: Composer?, %changed: Int, %default: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(B):Test.kt")
           if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -323,9 +272,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             B(%this%, %this%, %this%, a, b, c, %composer, %changed or 0b0001, %default)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -351,9 +297,6 @@
         """
             @Composable
             fun Test(foo: Foo, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)*<A()>:Test.kt")
               val %dirty = %changed
@@ -370,9 +313,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(foo, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -405,9 +345,6 @@
         """
             @Composable
             fun Test(foo: Foo, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)*<A()>,<B()>:Test.kt")
               val %dirty = %changed
@@ -427,9 +364,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(foo, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -454,9 +388,6 @@
         """
             @Composable
             fun Test(foo: Foo, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)*<A(2)>:Test.kt")
               val %dirty = %changed
@@ -473,9 +404,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(foo, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -505,9 +433,6 @@
         """
             @Composable
             fun Test(%this%: A, %this%: B, %this%: C, %this%: D, %this%: E, %this%: F, %this%: G, %this%: H, %this%: I, %this%: J, %this%: K, %this%: L, %composer: Composer?, %changed: Int, %changed1: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               if (%changed and 0b0001 !== 0 || %changed1 and 0b0001 !== 0 || !%composer.skipping) {
@@ -517,9 +442,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%this%, %this%, %this%, %this%, %this%, %this%, %this%, %this%, %this%, %this%, %this%, %this%, %composer, %changed or 0b0001, %changed1)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -540,9 +462,6 @@
             @Composable
             @ComposableInferredTarget(scheme = "[0[0]]")
             fun Test(%this%: Foo, a: String, b: Function3<String, Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<b("yay...>:Test.kt")
               val %dirty = %changed
@@ -557,9 +476,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%this%, a, b, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -594,9 +510,6 @@
         """
             @Composable
             fun Parent(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Parent)*<Test()>,<Test(a>,<Test(b>,<Test(a>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -612,15 +525,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Parent(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test(%this%: Foo, a: String?, b: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               val %dirty = %changed
@@ -656,9 +563,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%this%, a, b, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
index 9a9e0e5..c49caa0 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
@@ -1179,9 +1179,6 @@
         """
             @Composable
             fun Example(items: Iterator<Int>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)*<P(i)>,<P(l)>:Test.kt")
               while (items.hasNext()) {
@@ -1198,9 +1195,6 @@
                   %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                     Example(items, %composer, %changed or 0b0001)
                   }
-                  if (isTraceInProgress()) {
-                    traceEventEnd()
-                  }
                   return
                 } else {
                   %composer.startReplaceableGroup(<>)
@@ -1213,9 +1207,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(items, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2312,9 +2303,6 @@
         """
             @Composable
             fun Example(x: Int?, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)<A(c)>:Test.kt")
               val %dirty = %changed
@@ -2350,9 +2338,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2374,9 +2359,6 @@
         """
             @Composable
             fun Example(x: Int?, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)<A()>:Test.kt")
               val %dirty = %changed
@@ -2397,9 +2379,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2480,9 +2459,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<W>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -2493,9 +2469,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -2523,9 +2496,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<IW>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -2545,9 +2515,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2570,9 +2537,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<Wrap>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -2583,9 +2547,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -2633,9 +2594,6 @@
         """
             @Composable
             fun Test(value: InlineClass, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)P(0:InlineClass)<A()>:Test.kt")
               val %dirty = %changed
@@ -2651,9 +2609,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(value, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2809,9 +2764,6 @@
         """
             @Composable
             fun Test01(p0: Int, p1: Int, p2: Int, p3: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test01):Test.kt")
               val %dirty = %changed
@@ -2838,15 +2790,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test01(p0, p1, p2, p3, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test02(p0: Int, p1: Int, p3: Int, p2: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test02)P(!2,3):Test.kt")
               val %dirty = %changed
@@ -2873,15 +2819,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test02(p0, p1, p3, p2, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test03(p0: Int, p2: Int, p1: Int, p3: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test03)P(!1,2):Test.kt")
               val %dirty = %changed
@@ -2908,15 +2848,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test03(p0, p2, p1, p3, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test04(p0: Int, p2: Int, p3: Int, p1: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test04)P(!1,2,3):Test.kt")
               val %dirty = %changed
@@ -2943,15 +2877,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test04(p0, p2, p3, p1, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test05(p0: Int, p3: Int, p1: Int, p2: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test05)P(!1,3):Test.kt")
               val %dirty = %changed
@@ -2978,15 +2906,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test05(p0, p3, p1, p2, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test06(p0: Int, p3: Int, p2: Int, p1: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test06)P(!1,3,2):Test.kt")
               val %dirty = %changed
@@ -3013,15 +2935,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test06(p0, p3, p2, p1, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test07(p1: Int, p0: Int, p2: Int, p3: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test07)P(1):Test.kt")
               val %dirty = %changed
@@ -3048,15 +2964,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test07(p1, p0, p2, p3, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test08(p1: Int, p0: Int, p3: Int, p2: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test08)P(1!1,3):Test.kt")
               val %dirty = %changed
@@ -3083,15 +2993,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test08(p1, p0, p3, p2, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test09(p1: Int, p2: Int, p0: Int, p3: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test09)P(1,2):Test.kt")
               val %dirty = %changed
@@ -3118,15 +3022,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test09(p1, p2, p0, p3, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test00(p1: Int, p2: Int, p3: Int, p0: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test00)P(1,2,3):Test.kt")
               val %dirty = %changed
@@ -3153,15 +3051,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test00(p1, p2, p3, p0, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test11(p1: Int, p3: Int, p0: Int, p2: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test11)P(1,3):Test.kt")
               val %dirty = %changed
@@ -3188,15 +3080,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test11(p1, p3, p0, p2, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test12(p1: Int, p3: Int, p2: Int, p0: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test12)P(1,3,2):Test.kt")
               val %dirty = %changed
@@ -3223,15 +3109,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test12(p1, p3, p2, p0, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test13(p2: Int, p0: Int, p1: Int, p3: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test13)P(2):Test.kt")
               val %dirty = %changed
@@ -3258,15 +3138,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test13(p2, p0, p1, p3, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test14(p2: Int, p0: Int, p3: Int, p1: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test14)P(2!1,3):Test.kt")
               val %dirty = %changed
@@ -3293,15 +3167,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test14(p2, p0, p3, p1, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test15(p2: Int, p1: Int, p0: Int, p3: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test15)P(2,1):Test.kt")
               val %dirty = %changed
@@ -3328,15 +3196,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test15(p2, p1, p0, p3, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test16(p2: Int, p1: Int, p3: Int, p0: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test16)P(2,1,3):Test.kt")
               val %dirty = %changed
@@ -3363,15 +3225,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test16(p2, p1, p3, p0, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test17(p2: Int, p3: Int, p0: Int, p1: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test17)P(2,3):Test.kt")
               val %dirty = %changed
@@ -3398,15 +3254,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test17(p2, p3, p0, p1, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test18(p2: Int, p3: Int, p1: Int, p0: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test18)P(2,3,1):Test.kt")
               val %dirty = %changed
@@ -3433,15 +3283,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test18(p2, p3, p1, p0, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test19(p3: Int, p0: Int, p1: Int, p2: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test19)P(3):Test.kt")
               val %dirty = %changed
@@ -3468,15 +3312,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test19(p3, p0, p1, p2, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test20(p3: Int, p0: Int, p2: Int, p1: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test20)P(3!1,2):Test.kt")
               val %dirty = %changed
@@ -3503,15 +3341,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test20(p3, p0, p2, p1, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test21(p3: Int, p1: Int, p0: Int, p2: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test21)P(3,1):Test.kt")
               val %dirty = %changed
@@ -3538,15 +3370,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test21(p3, p1, p0, p2, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test22(p3: Int, p1: Int, p2: Int, p0: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test22)P(3,1,2):Test.kt")
               val %dirty = %changed
@@ -3573,15 +3399,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test22(p3, p1, p2, p0, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test23(p3: Int, p2: Int, p0: Int, p1: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test23)P(3,2):Test.kt")
               val %dirty = %changed
@@ -3608,15 +3428,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test23(p3, p2, p0, p1, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test24(p3: Int, p2: Int, p1: Int, p0: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test24)P(3,2,1):Test.kt")
               val %dirty = %changed
@@ -3643,9 +3457,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test24(p3, p2, p1, p0, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -3671,9 +3482,6 @@
         expectedTransformed = """
             @Composable
             fun Test(value: LocalInlineClass, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>, "androidx.compose.runtime.tests.Test (Test.kt:6)")
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)P(0:c#runtime.tests.LocalInlineClass):Test.kt#992ot2")
               val %dirty = %changed
@@ -3688,9 +3496,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(value, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         truncateTracingInfoMode = TruncateTracingInfoMode.KEEP_INFO_STRING
@@ -3719,9 +3524,6 @@
         expectedTransformed = """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>, "Test (Test.kt:4)")
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<b()>,<c()>,<d()>,<A(b(),>,<B()>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -3733,9 +3535,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         truncateTracingInfoMode = TruncateTracingInfoMode.KEEP_INFO_STRING
@@ -3833,9 +3632,6 @@
         expectedTransformed = """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>, "Test (Test.kt:4)")
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<W>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -3846,9 +3642,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -3925,9 +3718,6 @@
             }
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>, "Test (Test.kt:16)")
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<curren...>,<calcul...>,<Layout>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -3949,9 +3739,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         """
@@ -4041,9 +3828,6 @@
             }
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>, "Test (Test.kt:28)")
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<curren...>,<calcul...>,<Layout>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -4065,9 +3849,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         """
@@ -4131,9 +3912,6 @@
         expectedTransformed = """
             @Composable
             fun AttemptedToRealizeGroupTwice(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(AttemptedToRealizeGroupTwice)<Wrappe...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -4161,9 +3939,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 AttemptedToRealizeGroupTwice(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         extra = """
@@ -4200,9 +3975,6 @@
         """
             @Composable
             fun ArrayConstructorTest(n: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(ArrayConstructorTest)<rememb...>,<rememb...>,<rememb...>,<rememb...>,<rememb...>,<rememb...>,<rememb...>,<rememb...>,<rememb...>:Test.kt")
               val %dirty = %changed
@@ -4270,9 +4042,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 ArrayConstructorTest(n, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt
index a99f59d9..9a234ca 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt
@@ -33,9 +33,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)")
               if (%changed !== 0 || !%composer.skipping) {
@@ -47,9 +44,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -66,9 +60,6 @@
         """
             @Composable
             private fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               if (%changed !== 0 || !%composer.skipping) {
                 A(a, %composer, 0)
@@ -79,9 +70,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -99,9 +87,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)")
               if (%changed !== 0 || !%composer.skipping) {
@@ -112,9 +97,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -141,9 +123,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)")
               if (%changed !== 0 || !%composer.skipping) {
@@ -160,9 +139,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt
index 92d6b87..f021d5c 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt
@@ -63,9 +63,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A(1)>,<B()>,<B(2)>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -78,9 +75,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -103,9 +97,6 @@
         """
             @Composable
             fun Example(foo: Foo, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)P(0:Foo):Test.kt")
               val %dirty = %changed
@@ -125,15 +116,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(foo, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<Exampl...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -144,9 +129,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -166,9 +148,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A(0,>,<A(a>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -180,9 +159,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -227,9 +203,6 @@
         """
             @Composable
             fun Test(x: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               val %dirty = %changed
@@ -257,9 +230,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(x, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -278,9 +248,6 @@
         """
             @Composable
             fun A(a: Int, b: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A):Test.kt")
               val %dirty = %changed
@@ -317,9 +284,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(a, b, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -399,9 +363,6 @@
         """
             @Composable
             fun Example(a00: Int, a01: Int, a02: Int, a03: Int, a04: Int, a05: Int, a06: Int, a07: Int, a08: Int, a09: Int, a10: Int, a11: Int, a12: Int, a13: Int, a14: Int, a15: Int, a16: Int, a17: Int, a18: Int, a19: Int, a20: Int, a21: Int, a22: Int, a23: Int, a24: Int, a25: Int, a26: Int, a27: Int, a28: Int, a29: Int, a30: Int, %composer: Composer?, %changed: Int, %changed1: Int, %changed2: Int, %changed3: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example):Test.kt")
               val %dirty = %changed
@@ -694,9 +655,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, %composer, %changed or 0b0001, %changed1, %changed2, %changed3, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -778,9 +736,6 @@
         """
             @Composable
             fun Example(a00: Int, a01: Int, a02: Int, a03: Int, a04: Int, a05: Int, a06: Int, a07: Int, a08: Int, a09: Int, a10: Int, a11: Int, a12: Int, a13: Int, a14: Int, a15: Int, a16: Int, a17: Int, a18: Int, a19: Int, a20: Int, a21: Int, a22: Int, a23: Int, a24: Int, a25: Int, a26: Int, a27: Int, a28: Int, a29: Int, a30: Int, a31: Int, %composer: Composer?, %changed: Int, %changed1: Int, %changed2: Int, %changed3: Int, %default: Int, %default1: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example):Test.kt")
               val %dirty = %changed
@@ -1082,9 +1037,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, %composer, %changed or 0b0001, %changed1, %changed2, %changed3, %default, %default1)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1167,9 +1119,6 @@
         """
             @Composable
             fun Example(a00: Int, a01: Int, a02: Int, a03: Int, a04: Int, a05: Int, a06: Int, a07: Int, a08: Int, a09: Foo?, a10: Int, a11: Int, a12: Int, a13: Int, a14: Int, a15: Int, a16: Int, a17: Int, a18: Int, a19: Int, a20: Int, a21: Int, a22: Int, a23: Int, a24: Int, a25: Int, a26: Int, a27: Int, a28: Int, a29: Int, a30: Int, a31: Foo?, %composer: Composer?, %changed: Int, %changed1: Int, %changed2: Int, %changed3: Int, %default: Int, %default1: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example):Test.kt")
               val %dirty = %changed
@@ -1481,9 +1430,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, %composer, %changed or 0b0001, %changed1, %changed2, %changed3, %default, %default1)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
index d338b59..fa1da8c 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
@@ -72,9 +72,6 @@
         """
             @Composable
             fun Test(x: Int, y: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<Wrap>:Test.kt")
               val %dirty = %changed
@@ -120,9 +117,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(x, y, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -150,9 +144,6 @@
         """
             @Composable
             fun BasicText(style: TextStyle?, onTextLayout: Function1<TextLayoutResult, Unit>?, overflow: TextOverflow, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(BasicText)P(2!,1:c#ui.text.style.TextOverflow):Test.kt")
               val %dirty = %changed
@@ -191,9 +182,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 BasicText(style, onTextLayout, overflow, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -216,9 +204,6 @@
         """
             @Composable
             fun A(arrangement: Vertical?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A):Test.kt")
               val %dirty = %changed
@@ -238,9 +223,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(arrangement, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -261,9 +243,6 @@
             @Composable
             @ComposableInferredTarget(scheme = "[0[0]]")
             fun Example(content: Function2<Composer, Int, Unit>?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)<conten...>:Test.kt")
               val %dirty = %changed
@@ -283,9 +262,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(content, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -319,9 +295,6 @@
               Example(class <no name provided> : A {
                 @Composable
                 override fun compute(it: Int, %composer: Composer?, %changed: Int) {
-                  if (isTraceInProgress()) {
-                    traceEventStart(<>)
-                  }
                   %composer = %composer.startRestartGroup(<>)
                   sourceInformation(%composer, "C(compute)<comput...>:Test.kt")
                   val %dirty = %changed
@@ -337,9 +310,6 @@
                   %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                     tmp0_rcvr.compute(it, %composer, %changed or 0b0001)
                   }
-                  if (isTraceInProgress()) {
-                    traceEventEnd()
-                  }
                 }
               }
               <no name provided>())
@@ -377,9 +347,6 @@
             @Composable
             @ComposableInferredTarget(scheme = "[androidx.compose.ui.UiComposable[androidx.compose.ui.UiComposable]]")
             fun Button(colors: ButtonColors, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Button)<getCol...>,<Text("...>:Test.kt")
               val %dirty = %changed
@@ -394,16 +361,10 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Button(colors, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             @ComposableTarget(applier = "androidx.compose.ui.UiComposable")
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<Button>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -428,9 +389,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -516,9 +474,6 @@
             @Composable
             @ComposableInferredTarget(scheme = "[0[0]]")
             fun RowColumnImpl(orientation: LayoutOrientation, modifier: Modifier?, arrangement: Vertical?, crossAxisAlignment: Horizontal?, crossAxisSize: SizeMode?, content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(RowColumnImpl)P(5,4!1,2,3)<conten...>:Test.kt")
               val %dirty = %changed
@@ -577,16 +532,10 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 RowColumnImpl(orientation, modifier, arrangement, crossAxisAlignment, crossAxisSize, content, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             @ComposableInferredTarget(scheme = "[0[0]]")
             fun Column(modifier: Modifier?, verticalArrangement: Vertical?, horizontalGravity: Horizontal?, content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Column)P(2,3,1)<RowCol...>:Test.kt")
               val %dirty = %changed
@@ -629,9 +578,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Column(modifier, verticalArrangement, horizontalGravity, content, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -655,9 +601,6 @@
         """
             @Composable
             fun SimpleBox(modifier: Modifier?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(SimpleBox):Test.kt")
               val %dirty = %changed
@@ -677,9 +620,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 SimpleBox(modifier, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -698,9 +638,6 @@
         """
             @Composable
             fun Example(a: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example):Test.kt")
               val %dirty = %changed
@@ -728,9 +665,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(a, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -752,9 +686,6 @@
         """
             @Composable
             fun Example(a: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)<Inner(...>:Test.kt")
               val %dirty = %changed
@@ -776,9 +707,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(a, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -852,9 +780,6 @@
         """
             @Composable
             fun SimpleBox(modifier: Modifier?, shape: Shape?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(SimpleBox):Test.kt")
               val %dirty = %changed
@@ -891,9 +816,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 SimpleBox(modifier, shape, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -919,9 +841,6 @@
             @Composable
             @ComposableInferredTarget(scheme = "[0[0]]")
             fun SimpleBox(modifier: Modifier?, content: Function2<Composer, Int, Unit>?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(SimpleBox)P(1)<conten...>:Test.kt")
               val %dirty = %changed
@@ -950,9 +869,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 SimpleBox(modifier, content, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -1048,9 +964,6 @@
             @Composable
             @ComposableInferredTarget(scheme = "[0[0]]")
             fun SomeThing(content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(SomeThing)<conten...>:Test.kt")
               val %dirty = %changed
@@ -1065,15 +978,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 SomeThing(content, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Example(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)<SomeTh...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -1084,9 +991,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -1114,9 +1018,6 @@
         """
             @Composable
             fun B(values: IntArray, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B):Test.kt")
               val %dirty = %changed
@@ -1138,9 +1039,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 B(*values, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1160,9 +1058,6 @@
         """
             @Composable
             fun B(values: Array<out Foo>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B):Test.kt")
               val %dirty = %changed
@@ -1184,9 +1079,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 B(*values, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1205,18 +1097,12 @@
         """
             @Composable
             fun B(values: Array<out Foo>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B):Test.kt")
               print(values)
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 B(*values, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1242,9 +1128,6 @@
               var counter: Int = 0
               @Composable
               fun A(%composer: Composer?, %changed: Int) {
-                if (isTraceInProgress()) {
-                  traceEventStart(<>)
-                }
                 %composer = %composer.startRestartGroup(<>)
                 sourceInformation(%composer, "C(A):Test.kt")
                 if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -1256,15 +1139,9 @@
                 %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                   tmp0_rcvr.A(%composer, %changed or 0b0001)
                 }
-                if (isTraceInProgress()) {
-                  traceEventEnd()
-                }
               }
               @Composable
               fun B(%composer: Composer?, %changed: Int) {
-                if (isTraceInProgress()) {
-                  traceEventStart(<>)
-                }
                 %composer = %composer.startRestartGroup(<>)
                 sourceInformation(%composer, "C(B):Test.kt")
                 print(counter)
@@ -1272,9 +1149,6 @@
                 %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                   tmp0_rcvr.B(%composer, %changed or 0b0001)
                 }
-                if (isTraceInProgress()) {
-                  traceEventEnd()
-                }
               }
               static val %stable: Int = 8
             }
@@ -1297,9 +1171,6 @@
         """
             @Composable
             fun Example(a: Int, b: Int, c: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)<makeIn...>:Test.kt")
               val %dirty = %changed
@@ -1345,9 +1216,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(a, b, c, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1374,9 +1242,6 @@
             @Composable
             @ComposableInferredTarget(scheme = "[0[0]]")
             fun Wrap(y: Int, content: Function3<@[ParameterName(name = 'x')] Int, Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Wrap)P(1)<conten...>:Test.kt")
               val %dirty = %changed
@@ -1394,15 +1259,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Wrap(y, content, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test(x: Int, y: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<Wrap(1...>:Test.kt")
               val %dirty = %changed
@@ -1443,9 +1302,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(x, y, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1543,9 +1399,6 @@
         """
             @Composable
             fun Test(x: Int, y: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A(y>:Test.kt")
               val %dirty = %changed
@@ -1563,9 +1416,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(x, y, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1593,9 +1443,6 @@
         """
             @Composable
             fun CanSkip(a: Int, b: Foo?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(CanSkip):Test.kt")
               val %dirty = %changed
@@ -1632,15 +1479,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 CanSkip(a, b, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun CannotSkip(a: Int, b: Foo, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(CannotSkip):Test.kt")
               used(a)
@@ -1649,15 +1490,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 CannotSkip(a, b, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun NoParams(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(NoParams):Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -1668,9 +1503,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 NoParams(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1689,9 +1521,6 @@
         """
             @Composable
             fun Bar.CanSkip(b: Foo?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(CanSkip):Test.kt")
               val %dirty = %changed
@@ -1716,9 +1545,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 CanSkip(b, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1737,9 +1563,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A()>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -1750,9 +1573,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1771,9 +1591,6 @@
         """
             @Composable
             fun Test(x: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A(x)>:Test.kt")
               val %dirty = %changed
@@ -1788,9 +1605,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1819,9 +1633,6 @@
         """
             @Composable
             fun A(text: String, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)<B(text...>:Test.kt")
               val %dirty = %changed
@@ -1836,15 +1647,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(text, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun B(text: String, color: Color, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B)P(1,0:Color):Test.kt")
               val %dirty = %changed
@@ -1870,9 +1675,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 B(text, color, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1933,9 +1735,6 @@
         """
             @Composable
             fun A(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)<D>,<C({})>,<C(stab...>,<C(16.d...>,<C(Dp(1...>,<C(16.d...>,<C(norm...>,<C(Int....>,<C(stab...>,<C(Modi...>,<C(Foo....>,<C(cons...>,<C(123)>,<C(123>,<C(x)>,<C(x>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -1963,15 +1762,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun B(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(B)<C(Math...>,<C(Math...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -1983,9 +1776,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 B(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -2013,9 +1803,6 @@
         """
             @Composable
             fun Example(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)<D>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -2026,9 +1813,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -2058,9 +1842,6 @@
         """
             @Composable
             fun Test(x: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A(x)>:Test.kt")
               val %dirty = %changed
@@ -2080,9 +1861,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(x, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2102,9 +1880,6 @@
         """
             @Composable
             fun Test(x: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<I()>,<A(x)>:Test.kt")
               val %dirty = %changed
@@ -2132,9 +1907,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(x, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2154,18 +1926,12 @@
         """
             @Composable
             fun Test(x: Foo, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A(x)>:Test.kt")
               A(x, %composer, 0b1000)
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2185,9 +1951,6 @@
         """
             @Composable
             fun Test(x: Foo?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A(x)>:Test.kt")
               val %dirty = %changed
@@ -2215,9 +1978,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(x, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2237,9 +1997,6 @@
         """
             @Composable
             fun Test(a: Int, b: Boolean, c: Int, d: Foo?, e: List<Int>?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A(a,>:Test.kt")
               val %dirty = %changed
@@ -2295,9 +2052,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(a, b, c, d, e, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2316,9 +2070,6 @@
         """
             @Composable
             fun X(x: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(X)<X(x>,<X(x)>:Test.kt")
               val %dirty = %changed
@@ -2334,9 +2085,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 X(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2411,9 +2159,6 @@
         """
             @Composable
             fun Unstable.Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<doSome...>:Test.kt")
               val %dirty = %changed
@@ -2428,15 +2173,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun doSomething(x: Unstable, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(doSomething):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -2446,9 +2185,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 doSomething(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2525,9 +2261,6 @@
         """
             @Composable
             fun A(x: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)<B(>:Test.kt")
               val %dirty = %changed
@@ -2542,9 +2275,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2641,9 +2371,6 @@
         """
             @Composable
             fun A(x: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)<Provid...>,<B(x)>:Test.kt")
               val %dirty = %changed
@@ -2682,9 +2409,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2706,9 +2430,6 @@
         """
             @Composable
             fun A(x: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)<foo(x)>:Test.kt")
               val %dirty = %changed
@@ -2730,9 +2451,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -2801,9 +2519,6 @@
         """
             @Composable
             fun Example(a00: Int, a01: Int, a02: Int, a03: Int, a04: Int, a05: Int, a06: Int, a07: Int, a08: Int, a09: Int, a10: Int, a11: Int, a12: Int, a13: Int, a14: Int, %composer: Composer?, %changed: Int, %changed1: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)<Exampl...>,<Exampl...>:Test.kt")
               val %dirty = %changed
@@ -2937,9 +2652,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, %composer, %changed or 0b0001, %changed1, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -3011,9 +2723,6 @@
         """
             @Composable
             fun Example(a00: Int, a01: Int, a02: Int, a03: Int, a04: Int, a05: Int, a06: Int, a07: Int, a08: Int, a09: Int, a10: Int, a11: Int, a12: Int, a13: Int, a14: Int, a15: Int, %composer: Composer?, %changed: Int, %changed1: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)<Exampl...>,<Exampl...>:Test.kt")
               val %dirty = %changed
@@ -3155,9 +2864,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15, %composer, %changed or 0b0001, %changed1, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -3236,9 +2942,6 @@
         """
             @Composable
             fun Example(wontChange: Int, mightChange: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)P(1)<curren...>,<A(wont...>,<A(migh...>:Test.kt")
               val %dirty = %changed
@@ -3275,9 +2978,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(wontChange, mightChange, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -3295,9 +2995,6 @@
             @Composable
             @ComposableInferredTarget(scheme = "[0[0]]")
             fun Example(content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)<invoke...>:Test.kt")
               val %dirty = %changed
@@ -3312,9 +3009,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(content, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -3363,9 +3057,6 @@
             @Composable
             @ComposableInferredTarget(scheme = "[0[0]]")
             fun Box2(modifier: Modifier?, paddingStart: Dp, content: Function2<Composer, Int, Unit>?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Box2)P(1,2:c#ui.unit.Dp)<conten...>:Test.kt")
               val %dirty = %changed
@@ -3403,9 +3094,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Box2(modifier, paddingStart, content, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -3440,9 +3128,6 @@
         """
             @Composable
             fun Test(cond: Boolean, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<B()>:Test.kt")
               val %dirty = %changed
@@ -3465,9 +3150,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(cond, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -3498,24 +3180,15 @@
         """
             @Composable
             fun Unskippable(a: Unstable, b: Stable, c: MaybeStable, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Unskippable):Test.kt")
               used(a)
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Unskippable(a, b, c, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Skippable1(a: Unstable, b: Stable, c: MaybeStable, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Skippable1):Test.kt")
               val %dirty = %changed
@@ -3530,15 +3203,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Skippable1(a, b, c, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Skippable2(a: Unstable, b: Stable, c: MaybeStable, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Skippable2):Test.kt")
               val %dirty = %changed
@@ -3553,15 +3220,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Skippable2(a, b, c, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Skippable3(a: Unstable, b: Stable, c: MaybeStable, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Skippable3):Test.kt")
               if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -3571,9 +3232,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Skippable3(a, b, c, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -3596,9 +3254,6 @@
         """
             @Composable
             fun MaybeStable.example(x: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(example):Test.kt")
               val %dirty = %changed
@@ -3617,9 +3272,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 example(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             val example: @[ExtensionFunctionType] Function4<MaybeStable, Int, Composer, Int, Unit> = ComposableSingletons%TestKt.lambda-1
             internal object ComposableSingletons%TestKt {
@@ -3658,9 +3310,6 @@
         """
             @Composable
             fun VarargComposable(state: MutableState<Int>, values: Array<out String>?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(VarargComposable):Test.kt")
               val %dirty = %changed
@@ -3703,9 +3352,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 VarargComposable(state, *values, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
index a92ef628..6c23f3a 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
@@ -66,9 +66,6 @@
         """
             @Composable
             fun Example(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example):Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -106,9 +103,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         """
@@ -255,9 +249,6 @@
             @OptIn(markerClass = ExperimentalAnimationApi::class)
             @Composable
             fun SimpleAnimatedContentSample(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(SimpleAnimatedContentSample)<Animat...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -277,9 +268,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 SimpleAnimatedContentSample(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         """
@@ -303,9 +291,6 @@
         """
             @Composable
             fun A(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)<B>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -324,9 +309,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         """
@@ -385,9 +367,6 @@
         """
             @Composable
             fun A(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)<B(foo)>,<B(bar)>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -401,9 +380,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -442,9 +418,6 @@
         """
             @Composable
             fun A(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(A)<B>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -455,9 +428,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 A(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             internal object ComposableSingletons%TestKt {
               val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -492,9 +462,6 @@
         """
             @Composable
             fun Test(enabled: Boolean, content: Function2<Composer, Int, Unit>?, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)P(1)<Wrap(c...>:Test.kt")
               val %dirty = %changed
@@ -526,9 +493,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(enabled, content, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         """
@@ -555,9 +519,6 @@
         """
             @Composable
             fun Test(enabled: Boolean, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<Wrap(c...>:Test.kt")
               val %dirty = %changed
@@ -580,9 +541,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(enabled, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         """
@@ -614,9 +572,6 @@
         """
             @Composable
             fun TestLambda(content: Function0<Unit>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(TestLambda):Test.kt")
               val %dirty = %changed
@@ -631,15 +586,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 TestLambda(content, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<TestLa...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -652,9 +601,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
     """
     )
@@ -680,9 +626,6 @@
         """
         @Composable
         fun TestLambda(content: Function0<Unit>, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(TestLambda):Test.kt")
           val %dirty = %changed
@@ -697,15 +640,9 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             TestLambda(content, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         @Composable
         fun Test(a: String, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<{>,<TestLa...>:Test.kt")
           val %dirty = %changed
@@ -724,9 +661,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(a, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -748,9 +682,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)*<it()>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -783,9 +714,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         """
@@ -811,9 +739,6 @@
         """
             @Composable
             fun Test(s: String, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<rememb...>,<rememb...>,<curren...>:Test.kt")
               val %dirty = %changed
@@ -848,9 +773,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(s, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         """
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt
index 06a4583..1a6a8e7 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt
@@ -147,9 +147,6 @@
         """
             @Composable
             fun test1(x: KnownStable, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(test1):Test.kt")
               val %dirty = %changed
@@ -166,15 +163,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 test1(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun test2(x: KnownUnstable, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(test2):Test.kt")
               %composer.cache(%composer.changed(x)) {
@@ -183,15 +174,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 test2(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun test3(x: Uncertain, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(test3):Test.kt")
               val %dirty = %changed
@@ -208,9 +193,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 test3(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -316,9 +298,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A()>,<rememb...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -338,9 +317,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -362,9 +338,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -379,9 +352,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -401,9 +371,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<CInt()...>,<rememb...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -416,9 +383,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -442,9 +406,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<curren...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -458,9 +419,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -483,9 +441,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<curren...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -498,9 +453,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -521,9 +473,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A()>,<rememb...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -537,9 +486,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -562,9 +508,6 @@
         """
             @Composable
             fun Test(condition: Boolean, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A()>:Test.kt")
               val %dirty = %changed
@@ -584,9 +527,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(condition, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -609,9 +549,6 @@
         """
             @Composable
             fun Test(condition: Boolean, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A()>,<rememb...>:Test.kt")
               val %dirty = %changed
@@ -631,9 +568,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(condition, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -656,9 +590,6 @@
         """
             @Composable
             fun Test(items: List<Int>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)*<rememb...>:Test.kt")
               val tmp0_iterator = items.iterator()
@@ -673,9 +604,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(items, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -700,9 +628,6 @@
         """
             @Composable
             fun Test(items: List<Int>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)*<rememb...>,<A()>:Test.kt")
               val tmp0_iterator = items.iterator()
@@ -718,9 +643,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(items, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -740,9 +662,6 @@
         """
             @Composable
             fun Test(items: List<Int>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               val foo = %composer.cache(false) {
@@ -752,9 +671,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(items, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -774,9 +690,6 @@
         """
             @Composable
             fun Test(a: Int, b: Int, c: Bar, d: Boolean, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               val %dirty = %changed
@@ -802,9 +715,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(a, b, c, d, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -824,9 +734,6 @@
         """
             @Composable
             fun Test(items: Array<Bar>, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<rememb...>:Test.kt")
               val foo = remember(*items, {
@@ -835,9 +742,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(items, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -858,9 +762,6 @@
         """
             @Composable
             fun Test(inlineInt: InlineInt, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)P(0:InlineInt):Test.kt")
               val %dirty = %changed
@@ -878,9 +779,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(inlineInt, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -905,9 +803,6 @@
         """
             @Composable
             fun Test(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -927,9 +822,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -950,9 +842,6 @@
         """
             @Composable
             fun Test(a: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               val %dirty = %changed
@@ -970,9 +859,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(a, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1017,9 +903,6 @@
         """
             @Composable
             fun Test(a: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               val %dirty = %changed
@@ -1039,9 +922,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(a, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1060,9 +940,6 @@
         """
             @Composable
             fun Test(a: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               val %dirty = %changed
@@ -1077,9 +954,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(a, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1098,9 +972,6 @@
         """
             @Composable
             fun Test(a: Int, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               val %dirty = %changed
@@ -1118,9 +989,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(a, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1138,9 +1006,6 @@
         """
             @Composable
             fun Test(a: A, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test):Test.kt")
               val %dirty = %changed
@@ -1155,9 +1020,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(a, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -1179,9 +1041,6 @@
         """
             @Composable
             fun Test(a: Int, %composer: Composer?, %changed: Int, %default: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<rememb...>:Test.kt")
               val %dirty = %changed
@@ -1213,9 +1072,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(a, %composer, %changed or 0b0001, %default)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/StabilityPropagationTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/StabilityPropagationTransformTests.kt
index 963ccc0..10f5e0e 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/StabilityPropagationTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/StabilityPropagationTransformTests.kt
@@ -61,9 +61,6 @@
         """
         @Composable
         fun Test(x: Foo, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<A(x)>,<A(Foo(...>,<rememb...>,<A(reme...>:Test.kt")
           val %dirty = %changed
@@ -82,9 +79,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(x, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -108,9 +102,6 @@
         """
             @Composable
             fun Test(x: Foo, %composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Test)<A(x)>,<A(Foo(...>,<rememb...>,<A(reme...>:Test.kt")
               A(x, %composer, 0b1000)
@@ -121,9 +112,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Test(x, %composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
@@ -142,9 +130,6 @@
         """
             @Composable
             fun Example(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(Example)<A(list...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -155,9 +140,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 Example(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """
     )
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 d890675..0f25426 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
@@ -34,9 +34,6 @@
         @Composable
         @ComposableTarget(applier = "UI")
         fun Test(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<Text("...>:Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -47,9 +44,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -68,9 +62,6 @@
         @Composable
         @ComposableTarget(applier = "Vector")
         fun Test(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<Circle...>:Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -81,9 +72,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -100,9 +88,6 @@
         """
         @Composable
         fun Test(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test):Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -112,9 +97,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -133,9 +115,6 @@
         @Composable
         @ComposableInferredTarget(scheme = "[0[0]]")
         fun Test(content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<conten...>:Test.kt")
           val %dirty = %changed
@@ -150,9 +129,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(content, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -173,9 +149,6 @@
         @Composable
         @ComposableInferredTarget(scheme = "[UI[_]]")
         fun Test(content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<Row>:Test.kt")
           if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -186,9 +159,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(content, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         internal object ComposableSingletons%TestKt {
           val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -219,9 +189,6 @@
         @Composable
         @ComposableInferredTarget(scheme = "[UI[_]]")
         fun Test(content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<Inline...>:Test.kt")
           if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -241,9 +208,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(content, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -264,9 +228,6 @@
         @Composable
         @ComposableTarget(applier = "UI")
         fun Test(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<Wrappe...>:Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -277,9 +238,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         internal object ComposableSingletons%TestKt {
           val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -311,9 +269,6 @@
         @Composable
         @ComposableTarget(applier = "UI")
         fun Test(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<Compos...>:Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -328,9 +283,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         internal object ComposableSingletons%TestKt {
           val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -384,9 +336,6 @@
         @Composable
         @ComposableInferredTarget(scheme = "[0[0]]")
         fun OpenCustom(content: CustomComposable, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(OpenCustom)<call()>:Test.kt")
           val %dirty = %changed
@@ -401,16 +350,10 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             OpenCustom(content, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         @Composable
         @ComposableInferredTarget(scheme = "[UI[UI]]")
         fun ClosedCustom(content: CustomComposable, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(ClosedCustom)<Text("...>,<call()>:Test.kt")
           val %dirty = %changed
@@ -426,16 +369,10 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             ClosedCustom(content, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         @Composable
         @ComposableTarget(applier = "UI")
         fun Test(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<OpenCu...>,<Closed...>:Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -443,9 +380,6 @@
               @Composable
               @ComposableTarget(applier = "UI")
               override fun call(%composer: Composer?, %changed: Int) {
-                if (isTraceInProgress()) {
-                  traceEventStart(<>)
-                }
                 %composer = %composer.startRestartGroup(<>)
                 sourceInformation(%composer, "C(call)<Text("...>:Test.kt")
                 if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -457,9 +391,6 @@
                 %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                   tmp0_rcvr.call(%composer, %changed or 0b0001)
                 }
-                if (isTraceInProgress()) {
-                  traceEventEnd()
-                }
               }
             }
             <no name provided>(), %composer, 0)
@@ -467,9 +398,6 @@
               @Composable
               @ComposableTarget(applier = "UI")
               override fun call(%composer: Composer?, %changed: Int) {
-                if (isTraceInProgress()) {
-                  traceEventStart(<>)
-                }
                 %composer = %composer.startRestartGroup(<>)
                 sourceInformation(%composer, "C(call)<Text("...>:Test.kt")
                 if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -481,9 +409,6 @@
                 %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                   tmp0_rcvr.call(%composer, %changed or 0b0001)
                 }
-                if (isTraceInProgress()) {
-                  traceEventEnd()
-                }
               }
             }
             <no name provided>(), %composer, 0)
@@ -493,9 +418,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -513,9 +435,6 @@
         @Composable
         @ComposableInferredTarget(scheme = "[0[0]]")
         fun Test(content: Function2<Composer, Int, Unit?>, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)*<it()>:Test.kt")
           val %dirty = %changed
@@ -543,9 +462,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(content, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -604,9 +520,6 @@
         @Composable
         @ComposableTarget(applier = "UI")
         fun Leaf(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Leaf):Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -616,16 +529,10 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Leaf(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         @Composable
         @ComposableInferredTarget(scheme = "[0[0]]")
         fun Wrapper(content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Wrapper)<conten...>:Test.kt")
           val %dirty = %changed
@@ -640,16 +547,10 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Wrapper(content, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         @Composable
         @ComposableInferredTarget(scheme = "[0[0][0][0][0][0][0][0]]")
         fun Optional(one: Function2<Composer, Int, Unit>?, two: Function2<Composer, Int, Unit>?, three: Function2<Composer, Int, Unit>?, four: Function2<Composer, Int, Unit>?, five: Function2<Composer, Int, Unit>?, six: Function2<Composer, Int, Unit>?, content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int, %default: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Optional)P(3,6,5,2,1,4)<one()>,<conten...>:Test.kt")
           val %dirty = %changed
@@ -767,16 +668,10 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Optional(one, two, three, four, five, six, content, %composer, %changed or 0b0001, %default)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         @Composable
         @ComposableTarget(applier = "UI")
         fun UseOptional(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(UseOptional)<Option...>:Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -787,9 +682,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             UseOptional(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         internal object ComposableSingletons%TestKt {
           val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -952,9 +844,6 @@
         @Composable
         @ComposableTarget(applier = "androidx.compose.ui.UiComposable")
         fun Test1(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test1)<Layout...>:Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -979,16 +868,10 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test1(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         @Composable
         @ComposableInferredTarget(scheme = "[androidx.compose.ui.UiComposable[androidx.compose.ui.UiComposable]]")
         fun Test2(content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test2)<Layout...>:Test.kt")
           val %dirty = %changed
@@ -1008,16 +891,10 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test2(content, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         @Composable
         @ComposableTarget(applier = "androidx.compose.ui.UiComposable")
         fun Test3(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test3)<Test1(...>:Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -1028,16 +905,10 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test3(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         @Composable
         @ComposableTarget(applier = "androidx.compose.ui.UiComposable")
         fun Test4(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test4)<BasicT...>:Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -1050,9 +921,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test4(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         val Local: ProvidableCompositionLocal<Int> = compositionLocalOf {
           0
@@ -1060,9 +928,6 @@
         @Composable
         @ComposableInferredTarget(scheme = "[androidx.compose.ui.UiComposable[androidx.compose.ui.UiComposable]]")
         fun Test5(content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test5)<Compos...>:Test.kt")
           val %dirty = %changed
@@ -1085,16 +950,10 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test5(content, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         @Composable
         @ComposableTarget(applier = "androidx.compose.ui.UiComposable")
         fun Test6(test: String, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test6)<Compos...>:Test.kt")
           val %dirty = %changed
@@ -1117,15 +976,9 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test6(test, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         @Composable
         fun T(value: String, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(T):Test.kt")
           if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -1135,9 +988,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             T(value, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -1214,9 +1064,6 @@
         @Composable
         @ComposableInferredTarget(scheme = "[UI[UI]]")
         fun Test(content: Function2<Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<rememb...>:Test.kt")
           val %dirty = %changed
@@ -1248,9 +1095,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(content, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """
     )
@@ -1306,9 +1150,6 @@
         """
         @Composable
         fun Test(%composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<Widget...>:Test.kt")
           if (%changed !== 0 || !%composer.skipping) {
@@ -1319,9 +1160,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(%composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         """,
         extra = """
@@ -1350,9 +1188,6 @@
         @Composable
         @ComposableInferredTarget(scheme = "[UI[UI[UI]]]")
         fun Test(decorator: Function3<@[ParameterName(name = 'content')] Function2<Composer, Int, Unit>, Composer, Int, Unit>, %composer: Composer?, %changed: Int) {
-          if (isTraceInProgress()) {
-            traceEventStart(<>)
-          }
           %composer = %composer.startRestartGroup(<>)
           sourceInformation(%composer, "C(Test)<decora...>:Test.kt")
           val %dirty = %changed
@@ -1367,9 +1202,6 @@
           %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
             Test(decorator, %composer, %changed or 0b0001)
           }
-          if (isTraceInProgress()) {
-            traceEventEnd()
-          }
         }
         internal object ComposableSingletons%TestKt {
           val lambda-1: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, false) { %composer: Composer?, %changed: Int ->
@@ -1405,9 +1237,6 @@
         expectedTransformed = """
             @Composable
             fun NFromFile(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(NFromFile)<Open()>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -1418,15 +1247,9 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 NFromFile(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
             @Composable
             fun NFromInference(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(NFromInference)<N()>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -1437,9 +1260,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 NFromInference(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         extra = """
@@ -1472,9 +1292,6 @@
             @Composable
             @ComposableTarget(applier = "NComposable")
             fun InferN(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>)
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(InferN)<N()>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -1485,9 +1302,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 InferN(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         extra = """
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TraceInformationTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TraceInformationTest.kt
index 49695d9..d1ab22a 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TraceInformationTest.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TraceInformationTest.kt
@@ -44,9 +44,6 @@
             class A {
               @Composable
               fun B(x: Int, %composer: Composer?, %changed: Int) {
-                if (isTraceInProgress()) {
-                  traceEventStart(<>, -1, -1, "A.B (Test.kt:4)")
-                }
                 %composer = %composer.startRestartGroup(<>)
                 sourceInformation(%composer, "C(B):Test.kt")
                 if (%changed and 0b0001 !== 0 || !%composer.skipping) {
@@ -57,17 +54,11 @@
                 %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                   tmp0_rcvr.B(x, %composer, %changed or 0b0001)
                 }
-                if (isTraceInProgress()) {
-                  traceEventEnd()
-                }
               }
               static val %stable: Int = 0
             }
             @Composable
             fun C(%composer: Composer?, %changed: Int) {
-              if (isTraceInProgress()) {
-                traceEventStart(<>, -1, -1, "C (Test.kt:8)")
-              }
               %composer = %composer.startRestartGroup(<>)
               sourceInformation(%composer, "C(C)<B(1337...>:Test.kt")
               if (%changed !== 0 || !%composer.skipping) {
@@ -78,9 +69,6 @@
               %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                 C(%composer, %changed or 0b0001)
               }
-              if (isTraceInProgress()) {
-                traceEventEnd()
-              }
             }
         """,
         truncateTracingInfoMode = TruncateTracingInfoMode.TRUNCATE_KEY
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt
index 573991c..ef4ab64 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt
@@ -15,8 +15,5 @@
     val UPDATE_SCOPE = Name.identifier("updateScope")
     val SOURCEINFORMATION = "sourceInformation"
     val SOURCEINFORMATIONMARKERSTART = "sourceInformationMarkerStart"
-    val IS_TRACE_IN_PROGRESS = "isTraceInProgress"
-    val TRACE_EVENT_START = "traceEventStart"
-    val TRACE_EVENT_END = "traceEventEnd"
     val SOURCEINFORMATIONMARKEREND = "sourceInformationMarkerEnd"
 }
\ No newline at end of file
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 bc25e76..5952f84 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
@@ -153,7 +153,6 @@
 import org.jetbrains.kotlin.ir.util.getPropertyGetter
 import org.jetbrains.kotlin.ir.util.isLocal
 import org.jetbrains.kotlin.ir.util.isVararg
-import org.jetbrains.kotlin.ir.util.kotlinFqName
 import org.jetbrains.kotlin.ir.util.parentClassOrNull
 import org.jetbrains.kotlin.ir.util.patchDeclarationParents
 import org.jetbrains.kotlin.ir.util.properties
@@ -613,35 +612,6 @@
         ).map { it.owner }.first()
     }
 
-    private val isTraceInProgressFunction by guardedLazy {
-        getTopLevelFunctions(
-            ComposeFqNames.fqNameFor(KtxNameConventions.IS_TRACE_IN_PROGRESS)
-        ).map { it.owner }.singleOrNull {
-            it.valueParameters.isEmpty()
-        }
-    }
-
-    private val traceEventStartFunction by guardedLazy {
-        getTopLevelFunctions(
-            ComposeFqNames.fqNameFor(KtxNameConventions.TRACE_EVENT_START)
-        ).map { it.owner }.singleOrNull {
-            it.valueParameters.map { p -> p.type } == listOf(
-                context.irBuiltIns.intType,
-                context.irBuiltIns.intType,
-                context.irBuiltIns.intType,
-                context.irBuiltIns.stringType
-            )
-        }
-    }
-
-    private val traceEventEndFunction by guardedLazy {
-        getTopLevelFunctions(
-            ComposeFqNames.fqNameFor(KtxNameConventions.TRACE_EVENT_END)
-        ).map { it.owner }.singleOrNull {
-            it.valueParameters.isEmpty()
-        }
-    }
-
     private val sourceInformationMarkerEndFunction by guardedLazy {
         getTopLevelFunctions(
             ComposeFqNames.fqNameFor(KtxNameConventions.SOURCEINFORMATIONMARKEREND)
@@ -1206,7 +1176,6 @@
             body.startOffset,
             body.endOffset,
             listOfNotNull(
-                irTraceEventStart(irFunctionSourceKey(), declaration),
                 irStartRestartGroup(
                     body,
                     scope,
@@ -1750,7 +1719,6 @@
                     updateScopeFunction.symbol,
                     irLambda(lambda, updateScopeBlockType)
                 ),
-                irTraceEventEnd()
             )
         )
     }
@@ -1974,42 +1942,6 @@
         }
     }
 
-    private fun irIsTraceInProgress(): IrExpression? =
-        isTraceInProgressFunction?.let { irCall(it) }
-
-    private fun irIfTraceInProgress(body: IrExpression): IrExpression? =
-        irIsTraceInProgress()?.let { isTraceInProgress ->
-            irIf(isTraceInProgress, body)
-        }
-
-    @OptIn(ObsoleteDescriptorBasedAPI::class)
-    private fun irTraceEventStart(key: IrExpression, declaration: IrFunction): IrExpression? =
-        traceEventStartFunction?.let { traceEventStart ->
-            val startOffset = declaration.body!!.startOffset
-            val endOffset = declaration.body!!.endOffset
-
-            val name = declaration.kotlinFqName
-            val file = declaration.file.name
-            val line = declaration.file.fileEntry.getLineNumber(declaration.startOffset)
-            val traceInfo = "$name ($file:$line)" // TODO(174715171) decide on what to log
-            val dirty1 = irConst(-1) // placeholder TODO(228314276): implement
-            val dirty2 = irConst(-1) // placeholder TODO(228314276): implement
-
-            irIfTraceInProgress(
-                irCall(traceEventStart, startOffset, endOffset).also {
-                    it.putValueArgument(0, key)
-                    it.putValueArgument(1, dirty1)
-                    it.putValueArgument(2, dirty2)
-                    it.putValueArgument(3, irConst(traceInfo))
-                }
-            )
-        }
-
-    private fun irTraceEventEnd(): IrExpression? =
-        traceEventEndFunction?.let {
-            irIfTraceInProgress(irCall(it))
-        }
-
     private fun irSourceInformationMarkerEnd(
         element: IrElement,
     ): IrExpression {
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 f85c14f..898b9cd 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
@@ -56,7 +56,8 @@
                 ComposableDemo("Inside Dialog") { onNavigateUp ->
                     DialogInputFieldDemo(onNavigateUp)
                 },
-                ComposableDemo("Inside scrollable") { TextFieldsInScrollableDemo() }
+                ComposableDemo("Inside scrollable") { TextFieldsInScrollableDemo() },
+                ComposableDemo("Cursor configuration") { TextFieldCursorBlinkingDemo() }
             )
         ),
         ComposableDemo("Text Accessibility") { TextAccessibilityDemo() }
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextFieldCursorBlinkingDemo.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextFieldCursorBlinkingDemo.kt
new file mode 100644
index 0000000..9f54447
--- /dev/null
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextFieldCursorBlinkingDemo.kt
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+package androidx.compose.foundation.demos.text
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.text.BasicText
+import androidx.compose.foundation.text.BasicTextField
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+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.focus.onFocusChanged
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.sp
+import kotlinx.coroutines.delay
+
+@Preview
+@Composable
+fun TextFieldCursorBlinkingDemo() {
+    Column(Modifier.verticalScroll(rememberScrollState())) {
+        BasicText("Focus on any of the text fields below to observe cursor behavior.")
+        BasicText("All fields are not editable, with a fixed selection position")
+        Item("Default cursor") {
+            DefaultCursor()
+        }
+        Item("Color cursor") {
+            ColorCursor()
+        }
+        Item("Color changing cursor") {
+            RainbowCursor()
+        }
+        Item("Gradient Cursor") {
+            GradientCursor()
+        }
+        Item("Cursors don't blink when typing (fake typing)") {
+            TypingCursorNeverBlinks()
+        }
+        Item("Changing selection shows cursor") {
+            ChangingSelectionShowsCursor()
+        }
+    }
+}
+
+@Composable
+private fun Item(title: String, content: @Composable () -> Unit) {
+    Column {
+        BasicText(title, style = TextStyle.Default.copy(
+            color = Color(0xFFAAAAAA),
+            fontSize = 20.sp
+        ))
+        content()
+    }
+}
+
+@Composable
+private fun DefaultCursor() {
+    val textFieldValue = TextFieldValue(
+        text = "Normal blink",
+        selection = TextRange(3)
+    )
+    BasicTextField(value = textFieldValue, onValueChange = {})
+}
+
+@Composable
+private fun ColorCursor() {
+    val textFieldValue = TextFieldValue(
+        text = "Red cursor",
+        selection = TextRange(3)
+    )
+    BasicTextField(
+        value = textFieldValue,
+        onValueChange = {},
+        cursorBrush = SolidColor(Color.Red)
+    )
+}
+
+private val Red = Color(0xffE13C56)
+private val Orange = Color(0xffE16D3C)
+private val Yellow = Color(0xffE0AE04)
+private val Green = Color(0xff78AA04)
+private val Blue = Color(0xff4A7DCF)
+private val Purple = Color(0xff7B4397)
+private val Rainbow = listOf(Orange, Yellow, Green, Blue, Purple, Red)
+
+@Composable
+private fun RainbowCursor() {
+    val textFieldValue = TextFieldValue(
+        text = "Rainbow cursor",
+        selection = TextRange(3)
+    )
+
+    // don't animate each frame, as changing the brush resets the cursor timer
+    val color = remember { mutableStateOf(Red) }
+    var shouldAnimate by remember { mutableStateOf(false) }
+    LaunchedEffect(shouldAnimate) {
+        while (shouldAnimate) {
+            Rainbow.forEach {
+                color.value = it
+                // we don't control the timer, but sync with the BasicText timer of 1s blinks
+                delay(1000)
+            }
+        }
+    }
+    BasicTextField(
+        value = textFieldValue,
+        onValueChange = {},
+        cursorBrush = SolidColor(color.value),
+        modifier = Modifier.onFocusChanged { shouldAnimate = it.isFocused }
+    )
+}
+
+@Composable
+private fun GradientCursor() {
+    val textFieldValue = TextFieldValue(
+        text = "Gradient cursor",
+        selection = TextRange(3)
+    )
+
+    BasicTextField(
+        value = textFieldValue,
+        onValueChange = {},
+        cursorBrush = Brush.verticalGradient(colors = Rainbow),
+    )
+}
+
+@Composable
+fun TypingCursorNeverBlinks() {
+    var text by remember { mutableStateOf("") }
+    var animate by remember { mutableStateOf(false) }
+    LaunchedEffect(animate) {
+        while (animate) {
+            text = ""
+            listOf("Lorem ", "ipsum ", "was ", "here.").forEach { word ->
+                text += word
+                delay(500)
+            }
+        }
+    }
+    val textFieldValue = TextFieldValue(
+        text = text,
+        selection = TextRange(text.length),
+    )
+    BasicTextField(
+        value = textFieldValue,
+        onValueChange = {},
+        modifier = Modifier.onFocusChanged { animate = it.isFocused }
+    )
+}
+
+@Composable
+@Preview
+fun ChangingSelectionShowsCursor() {
+    val text = "Some longer text that takes a while to cursor through"
+    var selection by remember { mutableStateOf(TextRange(0)) }
+    LaunchedEffect(text) {
+        while (true) {
+            selection = TextRange((selection.start + 1) % text.length)
+            delay(500)
+        }
+    }
+    val textFieldValue = TextFieldValue(
+        text = text,
+        selection = selection
+    )
+    Column {
+        BasicTextField(
+            value = textFieldValue,
+            onValueChange = {},
+            textStyle = TextStyle.Default.copy(fontFamily = FontFamily.Monospace)
+        )
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextFieldsInScrollableDemo.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextFieldsInScrollableDemo.kt
index c23eb94..f094edb 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextFieldsInScrollableDemo.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextFieldsInScrollableDemo.kt
@@ -15,10 +15,19 @@
  */
 package androidx.compose.foundation.demos.text
 
+import android.content.Context
+import android.view.ViewGroup
+import android.widget.EditText
+import android.widget.LinearLayout
+import android.widget.ScrollView
 import androidx.compose.foundation.border
+import androidx.compose.foundation.demos.text.ScrollableType.EditTextsInScrollView
+import androidx.compose.foundation.demos.text.ScrollableType.LazyColumn
+import androidx.compose.foundation.demos.text.ScrollableType.ScrollableColumn
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.ime
 import androidx.compose.foundation.layout.padding
@@ -26,7 +35,7 @@
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
-import androidx.compose.material.Switch
+import androidx.compose.material.RadioButton
 import androidx.compose.material.Text
 import androidx.compose.material.TextField
 import androidx.compose.runtime.Composable
@@ -40,41 +49,54 @@
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.view.setMargins
 
 private enum class ScrollableType {
     ScrollableColumn,
-    LazyColumn
+    LazyColumn,
+    EditTextsInScrollView,
 }
 
-@Preview
+@Preview(showBackground = true)
 @Composable
 fun TextFieldsInScrollableDemo() {
     var scrollableType by remember { mutableStateOf(ScrollableType.values().first()) }
 
     Column(Modifier.windowInsetsPadding(WindowInsets.ime)) {
         Row(verticalAlignment = Alignment.CenterVertically) {
+            RadioButton(
+                selected = scrollableType == ScrollableColumn,
+                onClick = { scrollableType = ScrollableColumn }
+            )
             Text("Scrollable column")
-            Switch(
-                checked = scrollableType == ScrollableType.LazyColumn,
-                onCheckedChange = {
-                    scrollableType = if (it) {
-                        ScrollableType.LazyColumn
-                    } else {
-                        ScrollableType.ScrollableColumn
-                    }
-                })
+        }
+        Row(verticalAlignment = Alignment.CenterVertically) {
+            RadioButton(
+                selected = scrollableType == LazyColumn,
+                onClick = { scrollableType = LazyColumn }
+            )
             Text("LazyColumn")
         }
+        Row(verticalAlignment = Alignment.CenterVertically) {
+            RadioButton(
+                selected = scrollableType == EditTextsInScrollView,
+                onClick = { scrollableType = EditTextsInScrollView }
+            )
+            Text("ScrollView")
+        }
 
         when (scrollableType) {
-            ScrollableType.ScrollableColumn -> TextFieldInScrollableColumn()
-            ScrollableType.LazyColumn -> TextFieldInLazyColumn()
+            ScrollableColumn -> TextFieldInScrollableColumn()
+            LazyColumn -> TextFieldInLazyColumn()
+            EditTextsInScrollView -> EditTextsInScrollView()
         }
     }
 }
 
+@Preview(showBackground = true)
 @Composable
-fun TextFieldInScrollableColumn() {
+private fun TextFieldInScrollableColumn() {
     Column(
         Modifier.verticalScroll(rememberScrollState())
     ) {
@@ -84,8 +106,9 @@
     }
 }
 
+@Preview(showBackground = true)
 @Composable
-fun TextFieldInLazyColumn() {
+private fun TextFieldInLazyColumn() {
     LazyColumn {
         items(50) { index ->
             DemoTextField(index)
@@ -93,6 +116,12 @@
     }
 }
 
+@Preview(showBackground = true)
+@Composable
+private fun EditTextsInScrollView() {
+    AndroidView(::EditTextsInScrollableView, modifier = Modifier.fillMaxSize())
+}
+
 @Composable
 private fun DemoTextField(index: Int) {
     var text by rememberSaveable { mutableStateOf("") }
@@ -105,4 +134,27 @@
             .border(1.dp, Color.Black)
             .fillMaxWidth()
     )
-}
\ No newline at end of file
+}
+
+private class EditTextsInScrollableView(context: Context) : ScrollView(context) {
+    init {
+        val column = LinearLayout(context)
+        column.orientation = LinearLayout.VERTICAL
+        addView(
+            column, ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT
+            )
+        )
+
+        repeat(30) {
+            val text = EditText(context)
+            column.addView(text, LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT
+            ).also {
+                it.setMargins(20)
+            })
+        }
+    }
+}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldCursorTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldCursorTest.kt
index 79a28b5..7c4ccaa 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldCursorTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/TextFieldCursorTest.kt
@@ -311,21 +311,20 @@
 
         focusAndWait()
 
-        // cursor visible first 500 ms
+        // hide the cursor
         rule.mainClock.advanceTimeBy(500)
+        rule.mainClock.advanceTimeByFrame()
 
         // TODO(b/170298051) check here that cursor is visible when we have a way to control
         //  cursor position when sending a text
 
-        // change text field value
         rule.runOnIdle {
             textValue.value = textValue.value.copy(selection = TextRange(0))
         }
 
-        // cursor would have been invisible during next 500 ms if cursor blinks when selection
-        // changes.
-        // To prevent blinking when selection changes we restart animation when new symbol is typed.
-        rule.mainClock.advanceTimeBy(400)
+        // necessary for animation to start (shows cursor again)
+        rule.mainClock.advanceTimeByFrame()
+
         with(rule.density) {
             rule.onNode(hasSetTextAction())
                 .captureToImage()
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldCursor.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldCursor.kt
index 64dadea..3701e07 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldCursor.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldCursor.kt
@@ -46,6 +46,9 @@
     val isBrushSpecified = !(cursorBrush is SolidColor && cursorBrush.value.isUnspecified)
     if (state.hasFocus && value.selection.collapsed && isBrushSpecified) {
         LaunchedEffect(cursorBrush, value.annotatedString, value.selection) {
+            // ensure that the value is always 1f _this_ frame by calling snapTo
+            cursorAlpha.snapTo(1f)
+            // then start the cursor blinking on animation clock (500ms on to start)
             cursorAlpha.animateTo(0f, cursorAnimationSpec)
         }
         drawWithContent {
@@ -74,15 +77,14 @@
     }
 } else this
 
-private val cursorAnimationSpec: AnimationSpec<Float>
-    get() = infiniteRepeatable(
-        animation = keyframes {
-            durationMillis = 1000
-            1f at 0
-            1f at 499
-            0f at 500
-            0f at 999
-        }
-    )
+private val cursorAnimationSpec: AnimationSpec<Float> = infiniteRepeatable(
+    animation = keyframes {
+        durationMillis = 1000
+        1f at 0
+        1f at 499
+        0f at 500
+        0f at 999
+    }
+)
 
 internal val DefaultCursorThickness = 2.dp
diff --git a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/text/Text.kt b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/text/Text.kt
index c873817..929a459 100644
--- a/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/text/Text.kt
+++ b/compose/integration-tests/docs-snippets/src/main/java/androidx/compose/integration/docs/text/Text.kt
@@ -37,7 +37,10 @@
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Color.Companion.Blue
+import androidx.compose.ui.graphics.Shadow
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.ParagraphStyle
@@ -225,6 +228,24 @@
     }
 }
 
+private object TextShadowSnippet {
+    @Composable
+    fun TextShadow() {
+        val offset = Offset(5.0f, 10.0f)
+        Text(
+            text = "Hello world!",
+            style = TextStyle(
+                fontSize = 24.sp,
+                shadow = Shadow(
+                    color = Color.Blue,
+                    offset = offset,
+                    blurRadius = 3f
+                )
+            )
+        )
+    }
+}
+
 private object TextSelectableSnippet {
     @Composable
     fun SelectableText() {
diff --git a/compose/material/OWNERS b/compose/material/OWNERS
index 9e0b875..c12e7c5d 100644
--- a/compose/material/OWNERS
+++ b/compose/material/OWNERS
@@ -1,8 +1,10 @@
 # Bug component: 489623
+file: ../material3/OWNERS
+
 [email protected]
 [email protected]
 [email protected]
 [email protected]
 [email protected]
 [email protected]
[email protected]
\ No newline at end of file
[email protected]
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 b198cf5..d388ff5 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
@@ -1076,7 +1076,7 @@
             ProgressBarRangeInfo(
                 5f,
                 0f..10f,
-                3
+                1
             )
         )
 
@@ -1084,7 +1084,7 @@
             ProgressBarRangeInfo(
                 10f,
                 5f..20f,
-                3,
+                2,
             )
         )
 
@@ -1095,9 +1095,9 @@
             .performSemanticsAction(SemanticsActions.SetProgress) { it(15f) }
 
         rule.onAllNodes(isFocusable(), true)[0]
-            .assertRangeInfoEquals(ProgressBarRangeInfo(10f, 0f..15f, 3))
+            .assertRangeInfoEquals(ProgressBarRangeInfo(10f, 0f..15f, 2))
 
         rule.onAllNodes(isFocusable(), true)[1]
-            .assertRangeInfoEquals(ProgressBarRangeInfo(15f, 10f..20f, 3))
+            .assertRangeInfoEquals(ProgressBarRangeInfo(15f, 10f..20f, 1))
     }
 }
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 fd26414..b982fc1 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
@@ -93,6 +93,7 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.util.lerp
 import kotlin.math.abs
+import kotlin.math.floor
 import kotlin.math.max
 import kotlin.math.min
 import kotlinx.coroutines.CancellationException
@@ -162,7 +163,7 @@
         modifier
             .minimumTouchTargetSize()
             .requiredSizeIn(minWidth = ThumbRadius * 2, minHeight = ThumbRadius * 2)
-            .sliderSemantics(value, tickFractions, enabled, onValueChange, valueRange, steps)
+            .sliderSemantics(value, enabled, onValueChange, valueRange, steps)
             .focusable(enabled, interactionSource)
     ) {
         val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
@@ -399,21 +400,22 @@
         val coercedEnd = values.endInclusive.coerceIn(values.start, valueRange.endInclusive)
         val fractionStart = calcFraction(valueRange.start, valueRange.endInclusive, coercedStart)
         val fractionEnd = calcFraction(valueRange.start, valueRange.endInclusive, coercedEnd)
+        val startSteps = floor(steps * fractionEnd).toInt()
+        val endSteps = floor(steps * (1f - fractionStart)).toInt()
+
         val startThumbSemantics = Modifier.sliderSemantics(
             coercedStart,
-            tickFractions,
             enabled,
             { value -> onValueChangeState.value.invoke(value..coercedEnd) },
             valueRange.start..coercedEnd,
-            steps
+            startSteps
         )
         val endThumbSemantics = Modifier.sliderSemantics(
             coercedEnd,
-            tickFractions,
             enabled,
             { value -> onValueChangeState.value.invoke(coercedStart..value) },
             coercedStart..valueRange.endInclusive,
-            steps
+            endSteps
         )
 
         RangeSliderImpl(
@@ -632,7 +634,9 @@
         val offsetStart = widthDp * positionFractionStart
         val offsetEnd = widthDp * positionFractionEnd
         Track(
-            Modifier.align(Alignment.CenterStart).fillMaxSize(),
+            Modifier
+                .align(Alignment.CenterStart)
+                .fillMaxSize(),
             colors,
             enabled,
             positionFractionStart,
@@ -676,7 +680,10 @@
     enabled: Boolean,
     thumbSize: Dp
 ) {
-    Box(Modifier.padding(start = offset).align(Alignment.CenterStart)) {
+    Box(
+        Modifier
+            .padding(start = offset)
+            .align(Alignment.CenterStart)) {
         val interactions = remember { mutableStateListOf<Interaction>() }
         LaunchedEffect(interactionSource) {
             interactionSource.interactions.collect { interaction ->
@@ -833,7 +840,6 @@
 
 private fun Modifier.sliderSemantics(
     value: Float,
-    tickFractions: List<Float>,
     enabled: Boolean,
     onValueChange: (Float) -> Unit,
     valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
@@ -844,11 +850,21 @@
         if (!enabled) disabled()
         setProgress(
             action = { targetValue ->
-                val newValue = targetValue.coerceIn(valueRange.start, valueRange.endInclusive)
+                var newValue = targetValue.coerceIn(valueRange.start, valueRange.endInclusive)
+                val originalVal = newValue
                 val resolvedValue = if (steps > 0) {
-                    tickFractions
-                        .map { lerp(valueRange.start, valueRange.endInclusive, it) }
-                        .minByOrNull { abs(it - newValue) } ?: newValue
+                    var distance: Float = newValue
+                    for (i in 0..steps + 1) {
+                        val stepValue = lerp(
+                            valueRange.start,
+                            valueRange.endInclusive,
+                            i.toFloat() / (steps + 1))
+                        if (abs(stepValue - originalVal) <= distance) {
+                            distance = abs(stepValue - originalVal)
+                            newValue = stepValue
+                        }
+                    }
+                    newValue
                 } else {
                     newValue
                 }
@@ -1130,7 +1146,8 @@
 private val SliderHeight = 48.dp
 private val SliderMinWidth = 144.dp // TODO: clarify min width
 private val DefaultSliderConstraints =
-    Modifier.widthIn(min = SliderMinWidth)
+    Modifier
+        .widthIn(min = SliderMinWidth)
         .heightIn(max = SliderHeight)
 
 private val SliderToTickAnimation = TweenSpec<Float>(durationMillis = 100)
diff --git a/compose/material3/material3-window-size-class/api/current.txt b/compose/material3/material3-window-size-class/api/current.txt
index 03d5c5f..8522c90 100644
--- a/compose/material3/material3-window-size-class/api/current.txt
+++ b/compose/material3/material3-window-size-class/api/current.txt
@@ -7,41 +7,43 @@
   public final class TestOnly_jvmKt {
   }
 
-  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowHeightSizeClass {
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowHeightSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> {
+    method public operator int compareTo(int other);
     field public static final androidx.compose.material3.windowsizeclass.WindowHeightSizeClass.Companion Companion;
   }
 
   public static final class WindowHeightSizeClass.Companion {
-    method public String getCompact();
-    method public String getExpanded();
-    method public String getMedium();
-    property public final String Compact;
-    property public final String Expanded;
-    property public final String Medium;
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
   }
 
   @androidx.compose.runtime.Immutable public final class WindowSizeClass {
-    method public String getHeightSizeClass();
-    method public String getWidthSizeClass();
-    property public final String heightSizeClass;
-    property public final String widthSizeClass;
+    method public int getHeightSizeClass();
+    method public int getWidthSizeClass();
+    property public final int heightSizeClass;
+    property public final int widthSizeClass;
     field public static final androidx.compose.material3.windowsizeclass.WindowSizeClass.Companion Companion;
   }
 
   public static final class WindowSizeClass.Companion {
   }
 
-  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass {
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> {
+    method public operator int compareTo(int other);
     field public static final androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion Companion;
   }
 
   public static final class WindowWidthSizeClass.Companion {
-    method public String getCompact();
-    method public String getExpanded();
-    method public String getMedium();
-    property public final String Compact;
-    property public final String Expanded;
-    property public final String Medium;
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
   }
 
 }
diff --git a/compose/material3/material3-window-size-class/api/public_plus_experimental_current.txt b/compose/material3/material3-window-size-class/api/public_plus_experimental_current.txt
index 81439af8..e1590d8 100644
--- a/compose/material3/material3-window-size-class/api/public_plus_experimental_current.txt
+++ b/compose/material3/material3-window-size-class/api/public_plus_experimental_current.txt
@@ -11,24 +11,25 @@
   public final class TestOnly_jvmKt {
   }
 
-  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowHeightSizeClass {
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowHeightSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> {
+    method public operator int compareTo(int other);
     field public static final androidx.compose.material3.windowsizeclass.WindowHeightSizeClass.Companion Companion;
   }
 
   public static final class WindowHeightSizeClass.Companion {
-    method public String getCompact();
-    method public String getExpanded();
-    method public String getMedium();
-    property public final String Compact;
-    property public final String Expanded;
-    property public final String Medium;
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
   }
 
   @androidx.compose.runtime.Immutable public final class WindowSizeClass {
-    method public String getHeightSizeClass();
-    method public String getWidthSizeClass();
-    property public final String heightSizeClass;
-    property public final String widthSizeClass;
+    method public int getHeightSizeClass();
+    method public int getWidthSizeClass();
+    property public final int heightSizeClass;
+    property public final int widthSizeClass;
     field public static final androidx.compose.material3.windowsizeclass.WindowSizeClass.Companion Companion;
   }
 
@@ -36,17 +37,18 @@
     method @androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi @org.jetbrains.annotations.TestOnly public androidx.compose.material3.windowsizeclass.WindowSizeClass calculateFromSize(long size);
   }
 
-  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass {
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> {
+    method public operator int compareTo(int other);
     field public static final androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion Companion;
   }
 
   public static final class WindowWidthSizeClass.Companion {
-    method public String getCompact();
-    method public String getExpanded();
-    method public String getMedium();
-    property public final String Compact;
-    property public final String Expanded;
-    property public final String Medium;
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
   }
 
 }
diff --git a/compose/material3/material3-window-size-class/api/restricted_current.txt b/compose/material3/material3-window-size-class/api/restricted_current.txt
index 03d5c5f..8522c90 100644
--- a/compose/material3/material3-window-size-class/api/restricted_current.txt
+++ b/compose/material3/material3-window-size-class/api/restricted_current.txt
@@ -7,41 +7,43 @@
   public final class TestOnly_jvmKt {
   }
 
-  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowHeightSizeClass {
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowHeightSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowHeightSizeClass> {
+    method public operator int compareTo(int other);
     field public static final androidx.compose.material3.windowsizeclass.WindowHeightSizeClass.Companion Companion;
   }
 
   public static final class WindowHeightSizeClass.Companion {
-    method public String getCompact();
-    method public String getExpanded();
-    method public String getMedium();
-    property public final String Compact;
-    property public final String Expanded;
-    property public final String Medium;
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
   }
 
   @androidx.compose.runtime.Immutable public final class WindowSizeClass {
-    method public String getHeightSizeClass();
-    method public String getWidthSizeClass();
-    property public final String heightSizeClass;
-    property public final String widthSizeClass;
+    method public int getHeightSizeClass();
+    method public int getWidthSizeClass();
+    property public final int heightSizeClass;
+    property public final int widthSizeClass;
     field public static final androidx.compose.material3.windowsizeclass.WindowSizeClass.Companion Companion;
   }
 
   public static final class WindowSizeClass.Companion {
   }
 
-  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass {
+  @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public final value class WindowWidthSizeClass implements java.lang.Comparable<androidx.compose.material3.windowsizeclass.WindowWidthSizeClass> {
+    method public operator int compareTo(int other);
     field public static final androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion Companion;
   }
 
   public static final class WindowWidthSizeClass.Companion {
-    method public String getCompact();
-    method public String getExpanded();
-    method public String getMedium();
-    property public final String Compact;
-    property public final String Expanded;
-    property public final String Medium;
+    method public int getCompact();
+    method public int getExpanded();
+    method public int getMedium();
+    property public final int Compact;
+    property public final int Expanded;
+    property public final int Medium;
   }
 
 }
diff --git a/compose/material3/material3-window-size-class/samples/src/main/java/androidx/compose/material3/windowsizeclass/samples/WindowSizeClassSamples.kt b/compose/material3/material3-window-size-class/samples/src/main/java/androidx/compose/material3/windowsizeclass/samples/WindowSizeClassSamples.kt
index 9cfea24..7bf9334 100644
--- a/compose/material3/material3-window-size-class/samples/src/main/java/androidx/compose/material3/windowsizeclass/samples/WindowSizeClassSamples.kt
+++ b/compose/material3/material3-window-size-class/samples/src/main/java/androidx/compose/material3/windowsizeclass/samples/WindowSizeClassSamples.kt
@@ -36,12 +36,12 @@
                 // size changes, for example when the device is rotated, the value returned by
                 // calculateSizeClass will also change.
                 val windowSizeClass = calculateWindowSizeClass(this)
-                // Perform logic on the window size class to decide whether to show the top app bar.
-                val showTopAppBar = windowSizeClass.widthSizeClass != WindowWidthSizeClass.Compact
+                // Perform logic on the window size class to decide whether to use a nav rail.
+                val useNavRail = windowSizeClass.widthSizeClass > WindowWidthSizeClass.Compact
 
                 // MyScreen knows nothing about window size classes, and performs logic based on a
                 // Boolean flag.
-                MyScreen(showTopAppBar = showTopAppBar)
+                MyScreen(useNavRail = useNavRail)
             }
         }
     }
@@ -49,4 +49,4 @@
 
 @Suppress("UNUSED_PARAMETER")
 @Composable
-private fun MyScreen(showTopAppBar: Boolean) {}
+private fun MyScreen(useNavRail: Boolean) {}
diff --git a/compose/material3/material3-window-size-class/src/commonMain/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClass.kt b/compose/material3/material3-window-size-class/src/commonMain/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClass.kt
index 44bfcdb..c663e94 100644
--- a/compose/material3/material3-window-size-class/src/commonMain/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClass.kt
+++ b/compose/material3/material3-window-size-class/src/commonMain/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClass.kt
@@ -89,22 +89,35 @@
  */
 @Immutable
 @kotlin.jvm.JvmInline
-value class WindowWidthSizeClass private constructor(private val value: String) {
+value class WindowWidthSizeClass private constructor(private val value: Int) :
+    Comparable<WindowWidthSizeClass> {
+
+    override operator fun compareTo(other: WindowWidthSizeClass) = value.compareTo(other.value)
+
+    override fun toString(): String {
+        return "WindowWidthSizeClass." + when (this) {
+            Compact -> "Compact"
+            Medium -> "Medium"
+            Expanded -> "Expanded"
+            else -> ""
+        }
+    }
+
     companion object {
         /** Represents the majority of phones in portrait. */
-        val Compact = WindowWidthSizeClass("Compact")
+        val Compact = WindowWidthSizeClass(0)
 
         /**
          * Represents the majority of tablets in portrait and large unfolded inner displays in
          * portrait.
          */
-        val Medium = WindowWidthSizeClass("Medium")
+        val Medium = WindowWidthSizeClass(1)
 
         /**
          * Represents the majority of tablets in landscape and large unfolded inner displays in
          * landscape.
          */
-        val Expanded = WindowWidthSizeClass("Expanded")
+        val Expanded = WindowWidthSizeClass(2)
 
         /** Calculates the [WindowWidthSizeClass] for a given [width] */
         internal fun fromWidth(width: Dp): WindowWidthSizeClass {
@@ -129,16 +142,29 @@
  */
 @Immutable
 @kotlin.jvm.JvmInline
-value class WindowHeightSizeClass private constructor(private val value: String) {
+value class WindowHeightSizeClass private constructor(private val value: Int) :
+    Comparable<WindowHeightSizeClass> {
+
+    override operator fun compareTo(other: WindowHeightSizeClass) = value.compareTo(other.value)
+
+    override fun toString(): String {
+        return "WindowHeightSizeClass." + when (this) {
+            Compact -> "Compact"
+            Medium -> "Medium"
+            Expanded -> "Expanded"
+            else -> ""
+        }
+    }
+
     companion object {
         /** Represents the majority of phones in landscape */
-        val Compact = WindowHeightSizeClass("Compact")
+        val Compact = WindowHeightSizeClass(0)
 
         /** Represents the majority of tablets in landscape and majority of phones in portrait */
-        val Medium = WindowHeightSizeClass("Medium")
+        val Medium = WindowHeightSizeClass(1)
 
         /** Represents the majority of tablets in portrait */
-        val Expanded = WindowHeightSizeClass("Expanded")
+        val Expanded = WindowHeightSizeClass(2)
 
         /** Calculates the [WindowHeightSizeClass] for a given [height] */
         internal fun fromHeight(height: Dp): WindowHeightSizeClass {
diff --git a/compose/material3/material3-window-size-class/src/test/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClassTest.kt b/compose/material3/material3-window-size-class/src/test/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClassTest.kt
index a866f8f..b570d75 100644
--- a/compose/material3/material3-window-size-class/src/test/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClassTest.kt
+++ b/compose/material3/material3-window-size-class/src/test/kotlin/androidx/compose/material3/windowsizeclass/WindowSizeClassTest.kt
@@ -18,10 +18,10 @@
 
 import androidx.compose.ui.unit.dp
 import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
-import kotlin.test.assertFailsWith
 
 @RunWith(JUnit4::class)
 class WindowSizeClassTest {
@@ -67,4 +67,130 @@
         assertThat(WindowHeightSizeClass.fromHeight(1000.dp))
             .isEqualTo(WindowHeightSizeClass.Expanded)
     }
+
+    @Test
+    fun widthSizeClassToString() {
+        assertThat(WindowWidthSizeClass.Compact.toString())
+            .isEqualTo("WindowWidthSizeClass.Compact")
+        assertThat(WindowWidthSizeClass.Medium.toString())
+            .isEqualTo("WindowWidthSizeClass.Medium")
+        assertThat(WindowWidthSizeClass.Expanded.toString())
+            .isEqualTo("WindowWidthSizeClass.Expanded")
+    }
+
+    @Test
+    fun heightSizeClassToString() {
+        assertThat(WindowHeightSizeClass.Compact.toString())
+            .isEqualTo("WindowHeightSizeClass.Compact")
+        assertThat(WindowHeightSizeClass.Medium.toString())
+            .isEqualTo("WindowHeightSizeClass.Medium")
+        assertThat(WindowHeightSizeClass.Expanded.toString())
+            .isEqualTo("WindowHeightSizeClass.Expanded")
+    }
+
+    @Test
+    fun widthSizeClassCompareTo() {
+        // Less than
+        assertThat(WindowWidthSizeClass.Compact < WindowWidthSizeClass.Medium).isTrue()
+        assertThat(WindowWidthSizeClass.Compact < WindowWidthSizeClass.Expanded).isTrue()
+        assertThat(WindowWidthSizeClass.Medium < WindowWidthSizeClass.Expanded).isTrue()
+
+        assertThat(WindowWidthSizeClass.Compact < WindowWidthSizeClass.Compact).isFalse()
+        assertThat(WindowWidthSizeClass.Medium < WindowWidthSizeClass.Medium).isFalse()
+        assertThat(WindowWidthSizeClass.Expanded < WindowWidthSizeClass.Expanded).isFalse()
+
+        assertThat(WindowWidthSizeClass.Expanded < WindowWidthSizeClass.Medium).isFalse()
+        assertThat(WindowWidthSizeClass.Expanded < WindowWidthSizeClass.Compact).isFalse()
+        assertThat(WindowWidthSizeClass.Medium < WindowWidthSizeClass.Compact).isFalse()
+
+        // Less than or equal to
+        assertThat(WindowWidthSizeClass.Compact <= WindowWidthSizeClass.Compact).isTrue()
+        assertThat(WindowWidthSizeClass.Compact <= WindowWidthSizeClass.Medium).isTrue()
+        assertThat(WindowWidthSizeClass.Compact <= WindowWidthSizeClass.Expanded).isTrue()
+        assertThat(WindowWidthSizeClass.Medium <= WindowWidthSizeClass.Medium).isTrue()
+        assertThat(WindowWidthSizeClass.Medium <= WindowWidthSizeClass.Expanded).isTrue()
+        assertThat(WindowWidthSizeClass.Expanded <= WindowWidthSizeClass.Expanded).isTrue()
+
+        assertThat(WindowWidthSizeClass.Expanded <= WindowWidthSizeClass.Medium).isFalse()
+        assertThat(WindowWidthSizeClass.Expanded <= WindowWidthSizeClass.Compact).isFalse()
+        assertThat(WindowWidthSizeClass.Medium <= WindowWidthSizeClass.Compact).isFalse()
+
+        // Greater than
+        assertThat(WindowWidthSizeClass.Expanded > WindowWidthSizeClass.Medium).isTrue()
+        assertThat(WindowWidthSizeClass.Expanded > WindowWidthSizeClass.Compact).isTrue()
+        assertThat(WindowWidthSizeClass.Medium > WindowWidthSizeClass.Compact).isTrue()
+
+        assertThat(WindowWidthSizeClass.Expanded > WindowWidthSizeClass.Expanded).isFalse()
+        assertThat(WindowWidthSizeClass.Medium > WindowWidthSizeClass.Medium).isFalse()
+        assertThat(WindowWidthSizeClass.Compact > WindowWidthSizeClass.Compact).isFalse()
+
+        assertThat(WindowWidthSizeClass.Compact > WindowWidthSizeClass.Medium).isFalse()
+        assertThat(WindowWidthSizeClass.Compact > WindowWidthSizeClass.Expanded).isFalse()
+        assertThat(WindowWidthSizeClass.Medium > WindowWidthSizeClass.Expanded).isFalse()
+
+        // Greater than or equal to
+        assertThat(WindowWidthSizeClass.Expanded >= WindowWidthSizeClass.Expanded).isTrue()
+        assertThat(WindowWidthSizeClass.Expanded >= WindowWidthSizeClass.Medium).isTrue()
+        assertThat(WindowWidthSizeClass.Expanded >= WindowWidthSizeClass.Compact).isTrue()
+        assertThat(WindowWidthSizeClass.Medium >= WindowWidthSizeClass.Medium).isTrue()
+        assertThat(WindowWidthSizeClass.Medium >= WindowWidthSizeClass.Compact).isTrue()
+        assertThat(WindowWidthSizeClass.Compact >= WindowWidthSizeClass.Compact).isTrue()
+
+        assertThat(WindowWidthSizeClass.Compact >= WindowWidthSizeClass.Medium).isFalse()
+        assertThat(WindowWidthSizeClass.Compact >= WindowWidthSizeClass.Expanded).isFalse()
+        assertThat(WindowWidthSizeClass.Medium >= WindowWidthSizeClass.Expanded).isFalse()
+    }
+
+    @Test
+    fun heightSizeClassCompareTo() {
+        // Less than
+        assertThat(WindowHeightSizeClass.Compact < WindowHeightSizeClass.Medium).isTrue()
+        assertThat(WindowHeightSizeClass.Compact < WindowHeightSizeClass.Expanded).isTrue()
+        assertThat(WindowHeightSizeClass.Medium < WindowHeightSizeClass.Expanded).isTrue()
+
+        assertThat(WindowHeightSizeClass.Compact < WindowHeightSizeClass.Compact).isFalse()
+        assertThat(WindowHeightSizeClass.Medium < WindowHeightSizeClass.Medium).isFalse()
+        assertThat(WindowHeightSizeClass.Expanded < WindowHeightSizeClass.Expanded).isFalse()
+
+        assertThat(WindowHeightSizeClass.Expanded < WindowHeightSizeClass.Medium).isFalse()
+        assertThat(WindowHeightSizeClass.Expanded < WindowHeightSizeClass.Compact).isFalse()
+        assertThat(WindowHeightSizeClass.Medium < WindowHeightSizeClass.Compact).isFalse()
+
+        // Less than or equal to
+        assertThat(WindowHeightSizeClass.Compact <= WindowHeightSizeClass.Compact).isTrue()
+        assertThat(WindowHeightSizeClass.Compact <= WindowHeightSizeClass.Medium).isTrue()
+        assertThat(WindowHeightSizeClass.Compact <= WindowHeightSizeClass.Expanded).isTrue()
+        assertThat(WindowHeightSizeClass.Medium <= WindowHeightSizeClass.Medium).isTrue()
+        assertThat(WindowHeightSizeClass.Medium <= WindowHeightSizeClass.Expanded).isTrue()
+        assertThat(WindowHeightSizeClass.Expanded <= WindowHeightSizeClass.Expanded).isTrue()
+
+        assertThat(WindowHeightSizeClass.Expanded <= WindowHeightSizeClass.Medium).isFalse()
+        assertThat(WindowHeightSizeClass.Expanded <= WindowHeightSizeClass.Compact).isFalse()
+        assertThat(WindowHeightSizeClass.Medium <= WindowHeightSizeClass.Compact).isFalse()
+
+        // Greater than
+        assertThat(WindowHeightSizeClass.Expanded > WindowHeightSizeClass.Medium).isTrue()
+        assertThat(WindowHeightSizeClass.Expanded > WindowHeightSizeClass.Compact).isTrue()
+        assertThat(WindowHeightSizeClass.Medium > WindowHeightSizeClass.Compact).isTrue()
+
+        assertThat(WindowHeightSizeClass.Expanded > WindowHeightSizeClass.Expanded).isFalse()
+        assertThat(WindowHeightSizeClass.Medium > WindowHeightSizeClass.Medium).isFalse()
+        assertThat(WindowHeightSizeClass.Compact > WindowHeightSizeClass.Compact).isFalse()
+
+        assertThat(WindowHeightSizeClass.Compact > WindowHeightSizeClass.Medium).isFalse()
+        assertThat(WindowHeightSizeClass.Compact > WindowHeightSizeClass.Expanded).isFalse()
+        assertThat(WindowHeightSizeClass.Medium > WindowHeightSizeClass.Expanded).isFalse()
+
+        // Greater than or equal to
+        assertThat(WindowHeightSizeClass.Expanded >= WindowHeightSizeClass.Expanded).isTrue()
+        assertThat(WindowHeightSizeClass.Expanded >= WindowHeightSizeClass.Medium).isTrue()
+        assertThat(WindowHeightSizeClass.Expanded >= WindowHeightSizeClass.Compact).isTrue()
+        assertThat(WindowHeightSizeClass.Medium >= WindowHeightSizeClass.Medium).isTrue()
+        assertThat(WindowHeightSizeClass.Medium >= WindowHeightSizeClass.Compact).isTrue()
+        assertThat(WindowHeightSizeClass.Compact >= WindowHeightSizeClass.Compact).isTrue()
+
+        assertThat(WindowHeightSizeClass.Compact >= WindowHeightSizeClass.Medium).isFalse()
+        assertThat(WindowHeightSizeClass.Compact >= WindowHeightSizeClass.Expanded).isFalse()
+        assertThat(WindowHeightSizeClass.Medium >= WindowHeightSizeClass.Expanded).isFalse()
+    }
 }
\ No newline at end of file
diff --git a/compose/material3/material3/api/public_plus_experimental_current.txt b/compose/material3/material3/api/public_plus_experimental_current.txt
index a2efd3e..de30072 100644
--- a/compose/material3/material3/api/public_plus_experimental_current.txt
+++ b/compose/material3/material3/api/public_plus_experimental_current.txt
@@ -172,7 +172,7 @@
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ElevatedFilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? selectedIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipBorder? border, optional androidx.compose.material3.SelectableChipColors colors);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void ElevatedSuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.material3.ChipColors colors);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void FilterChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? selectedIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipBorder? border, optional androidx.compose.material3.SelectableChipColors colors);
-    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void InputChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? avatar, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.material3.ChipColors colors);
+    method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void InputChip(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon, optional kotlin.jvm.functions.Function0<kotlin.Unit>? avatar, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.SelectableChipElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.SelectableChipBorder? border, optional androidx.compose.material3.SelectableChipColors colors);
     method @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SuggestionChip(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? icon, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.material3.ChipElevation? elevation, optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.material3.ChipBorder? border, optional androidx.compose.material3.ChipColors colors);
   }
 
@@ -338,10 +338,10 @@
   }
 
   @androidx.compose.material3.ExperimentalMaterial3Api public final class FilterChipDefaults {
-    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors elevatedFilterChipColors(optional long containerColor, optional long labelColor, optional long iconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors elevatedFilterChipColors(optional long containerColor, optional long labelColor, optional long iconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation elevatedFilterChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipBorder filterChipBorder(optional long borderColor, optional long selectedBorderColor, optional long disabledBorderColor, optional long disabledSelectedBorderColor, optional float borderWidth, optional float selectedBorderWidth);
-    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors filterChipColors(optional long containerColor, optional long labelColor, optional long iconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors filterChipColors(optional long containerColor, optional long labelColor, optional long iconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
     method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation filterChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
     method public float getHeight();
     method public float getIconSize();
@@ -416,9 +416,9 @@
     method public float getAvatarSize();
     method public float getHeight();
     method public float getIconSize();
-    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipBorder inputChipBorder(optional long borderColor, optional long disabledBorderColor, optional float borderWidth);
-    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipColors inputChipColors(optional long containerColor, optional long labelColor, optional long leadingIconContentColor, optional long trailingIconContentColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconContentColor, optional long disabledTrailingIconContentColor);
-    method @androidx.compose.runtime.Composable public androidx.compose.material3.ChipElevation inputChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipBorder inputChipBorder(optional long borderColor, optional long selectedBorderColor, optional long disabledBorderColor, optional long disabledSelectedBorderColor, optional float borderWidth, optional float selectedBorderWidth);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipColors inputChipColors(optional long containerColor, optional long labelColor, optional long leadingIconColor, optional long trailingIconColor, optional long disabledContainerColor, optional long disabledLabelColor, optional long disabledLeadingIconColor, optional long disabledTrailingIconColor, optional long selectedContainerColor, optional long disabledSelectedContainerColor, optional long selectedLabelColor, optional long selectedLeadingIconColor, optional long selectedTrailingIconColor);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.SelectableChipElevation inputChipElevation(optional float defaultElevation, optional float pressedElevation, optional float focusedElevation, optional float hoveredElevation, optional float draggedElevation, optional float disabledElevation);
     property public final float AvatarSize;
     property public final float Height;
     property public final float IconSize;
diff --git a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/ColorSchemeDemo.kt b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/ColorSchemeDemo.kt
index e6ac3d0..9dbadaf 100644
--- a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/ColorSchemeDemo.kt
+++ b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/ColorSchemeDemo.kt
@@ -44,36 +44,32 @@
     ) {
         Column(Modifier.weight(1f).verticalScroll(rememberScrollState())) {
             Text("Surfaces", style = MaterialTheme.typography.bodyLarge)
-            ColorTile(
-                text = "On Background",
-                color = colorScheme.onBackground,
+            SurfaceColorSwatch(
+                surface = colorScheme.background,
+                surfaceText = "Background",
+                onSurface = colorScheme.onBackground,
+                onSurfaceText = "On Background"
             )
-            ColorTile(
-                text = "Background",
-                color = colorScheme.background,
+            Spacer(modifier = Modifier.height(16.dp))
+            SurfaceColorSwatch(
+                surface = colorScheme.surface,
+                surfaceText = "Surface",
+                onSurface = colorScheme.onSurface,
+                onSurfaceText = "On Surface"
+            )
+            Spacer(modifier = Modifier.height(16.dp))
+            SurfaceColorSwatch(
+                surface = colorScheme.surfaceVariant,
+                surfaceText = "Surface Variant",
+                onSurface = colorScheme.onSurfaceVariant,
+                onSurfaceText = "On Surface Variant"
             )
             Spacer(modifier = Modifier.height(16.dp))
             DoubleTile(
                 leftTile = {
                     ColorTile(
-                        text = "On Surface",
-                        color = colorScheme.onSurface,
-                    )
-                },
-                rightTile = {
-                    ColorTile(
-                        text = "On Surface Variant",
-                        color = colorScheme.onSurfaceVariant,
-                    )
-                },
-            )
-            ColorTile(text = "Surface", color = colorScheme.surface)
-            Spacer(modifier = Modifier.height(16.dp))
-            DoubleTile(
-                leftTile = {
-                    ColorTile(
-                        text = "Inverse Primary",
-                        color = colorScheme.inversePrimary,
+                        text = "Inverse Surface",
+                        color = colorScheme.inverseSurface,
                     )
                 },
                 rightTile = {
@@ -86,147 +82,130 @@
             DoubleTile(
                 leftTile = {
                     ColorTile(
-                        text = "Surface Variant",
-                        color = colorScheme.surfaceVariant,
+                        text = "Inverse Primary",
+                        color = colorScheme.inversePrimary,
                     )
                 },
                 rightTile = {
                     ColorTile(
-                        text = "Inverse Surface",
-                        color = colorScheme.inverseSurface,
-                    )
-                },
-            )
-            Spacer(modifier = Modifier.height(16.dp))
-            DoubleTile(
-                leftTile = {
-                    ColorTile(
                         text = "Surface Tint",
                         color = colorScheme.surfaceTint,
                     )
                 },
-                rightTile = { Box(Modifier.fillMaxWidth()) },
             )
+            Spacer(modifier = Modifier.height(16.dp))
         }
         Spacer(modifier = Modifier.width(24.dp))
         Column(Modifier.weight(1f).verticalScroll(rememberScrollState())) {
             Text("Content", style = MaterialTheme.typography.bodyLarge)
-            DoubleTile(
-                leftTile = {
-                    ColorTile(
-                        text = "On Primary Container",
-                        color = colorScheme.onPrimaryContainer,
-                    )
-                },
-                rightTile = {
-                    ColorTile(
-                        text = "On Primary",
-                        color = colorScheme.onPrimary,
-                    )
-                },
-            )
-            DoubleTile(
-                leftTile = {
-                    ColorTile(
-                        text = "Primary Container",
-                        color = colorScheme.primaryContainer,
-                    )
-                },
-                rightTile = {
-                    ColorTile(
-                        text = "Primary",
-                        color = colorScheme.primary,
-                    )
-                },
-            )
+            ContentColorSwatch(
+                color = colorScheme.primary,
+                colorText = "Primary",
+                onColor = colorScheme.onPrimary,
+                onColorText = "On Primary",
+                colorContainer = colorScheme.primaryContainer,
+                colorContainerText = "Primary Container",
+                onColorContainer = colorScheme.onPrimaryContainer,
+                onColorContainerText = "On Primary Container")
             Spacer(modifier = Modifier.height(16.dp))
-            DoubleTile(
-                leftTile = {
-                    ColorTile(
-                        text = "On Secondary Container",
-                        color = colorScheme.onSecondaryContainer,
-                    )
-                },
-                rightTile = {
-                    ColorTile(
-                        text = "On Secondary",
-                        color = colorScheme.onSecondary,
-                    )
-                },
-            )
-            DoubleTile(
-                leftTile = {
-                    ColorTile(
-                        text = "Secondary Container",
-                        color = colorScheme.secondaryContainer,
-                    )
-                },
-                rightTile = {
-                    ColorTile(
-                        text = "Secondary",
-                        color = colorScheme.secondary,
-                    )
-                },
-            )
+            ContentColorSwatch(
+                color = colorScheme.secondary,
+                colorText = "Secondary",
+                onColor = colorScheme.onSecondary,
+                onColorText = "On Secondary",
+                colorContainer = colorScheme.secondaryContainer,
+                colorContainerText = "Secondary Container",
+                onColorContainer = colorScheme.onSecondaryContainer,
+                onColorContainerText = "On Secondary Container")
             Spacer(modifier = Modifier.height(16.dp))
-            DoubleTile(
-                leftTile = {
-                    ColorTile(
-                        text = "On Tertiary Container",
-                        color = colorScheme.onTertiaryContainer,
-                    )
-                },
-                rightTile = {
-                    ColorTile(
-                        text = "On Tertiary",
-                        color = colorScheme.onTertiary,
-                    )
-                },
-            )
-            DoubleTile(
-                leftTile = {
-                    ColorTile(
-                        text = "Tertiary Container",
-                        color = colorScheme.tertiaryContainer,
-                    )
-                },
-                rightTile = {
-                    ColorTile(
-                        text = "Tertiary",
-                        color = colorScheme.tertiary,
-                    )
-                },
-            )
+            ContentColorSwatch(
+                color = colorScheme.tertiary,
+                colorText = "Tertiary",
+                onColor = colorScheme.onTertiary,
+                onColorText = "On Tertiary",
+                colorContainer = colorScheme.tertiaryContainer,
+                colorContainerText = "Tertiary Container",
+                onColorContainer = colorScheme.onTertiaryContainer,
+                onColorContainerText = "On Tertiary Container")
+            Spacer(modifier = Modifier.height(16.dp))
+            ContentColorSwatch(
+                color = colorScheme.error,
+                colorText = "Error",
+                onColor = colorScheme.onError,
+                onColorText = "On Error",
+                colorContainer = colorScheme.errorContainer,
+                colorContainerText = "Error Container",
+                onColorContainer = colorScheme.onErrorContainer,
+                onColorContainerText = "On Error Container")
             Spacer(modifier = Modifier.height(16.dp))
             Text("Utility", style = MaterialTheme.typography.bodyLarge)
-            DoubleTile(
-                leftTile = {
-                    ColorTile(
-                        text = "On Error",
-                        color = colorScheme.onError,
-                    )
-                },
-                rightTile = {
-                    ColorTile(
-                        text = "Outline",
-                        color = colorScheme.outline,
-                    )
-                }
-            )
-            DoubleTile(
-                leftTile = {
-                    ColorTile(
-                        text = "Error",
-                        color = colorScheme.error,
-                    )
-                },
-                rightTile = { Box(Modifier.fillMaxWidth()) },
+            ColorTile(
+                text = "Outline",
+                color = colorScheme.outline,
             )
         }
     }
 }
 
 @Composable
+private fun SurfaceColorSwatch(
+    surface: Color,
+    surfaceText: String,
+    onSurface: Color,
+    onSurfaceText: String
+) {
+    ColorTile(
+        text = surfaceText,
+        color = surface,
+    )
+    ColorTile(
+        text = onSurfaceText,
+        color = onSurface,
+    )
+}
+
+@Composable
+private fun ContentColorSwatch(
+    color: Color,
+    colorText: String,
+    onColor: Color,
+    onColorText: String,
+    colorContainer: Color,
+    colorContainerText: String,
+    onColorContainer: Color,
+    onColorContainerText: String,
+) {
+    DoubleTile(
+        leftTile = {
+            ColorTile(
+                text = colorText,
+                color = color
+            )
+        },
+        rightTile = {
+            ColorTile(
+                text = onColorText,
+                color = onColor,
+            )
+        },
+    )
+    DoubleTile(
+        leftTile = {
+            ColorTile(
+                text = colorContainerText,
+                color = colorContainer,
+            )
+        },
+        rightTile = {
+            ColorTile(
+                text = onColorContainerText,
+                color = onColorContainer,
+            )
+        },
+    )
+}
+
+@Composable
 private fun DoubleTile(leftTile: @Composable () -> Unit, rightTile: @Composable () -> Unit) {
     Row(modifier = Modifier.fillMaxWidth()) {
         Box(modifier = Modifier.weight(1f)) { leftTile() }
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ChipSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ChipSamples.kt
index 0c48d88..a0e996c 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ChipSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/ChipSamples.kt
@@ -153,8 +153,10 @@
 @Sampled
 @Composable
 fun InputChipSample() {
+    var selected by remember { mutableStateOf(false) }
     InputChip(
-        onClick = { /* Do something! */ },
+        selected = selected,
+        onClick = { selected = !selected },
         label = { Text("Input Chip") },
         trailingIcon = {
             Icon(
@@ -170,8 +172,10 @@
 @Sampled
 @Composable
 fun InputChipWithAvatarSample() {
+    var selected by remember { mutableStateOf(false) }
     InputChip(
-        onClick = { /* Do something! */ },
+        selected = selected,
+        onClick = { selected = !selected },
         label = { Text("Input Chip") },
         avatar = {
             Icon(
@@ -217,7 +221,7 @@
     Column(horizontalAlignment = Alignment.CenterHorizontally) {
         Row(modifier = Modifier.horizontalScroll(rememberScrollState())) {
             repeat(9) { index ->
-                InputChip(
+                AssistChip(
                     modifier = Modifier.padding(horizontal = 4.dp),
                     onClick = { /* do something*/ },
                     label = { Text("Chip $index") }
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ChipScreenshotTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ChipScreenshotTest.kt
index 23d66f4e..e1d448a 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ChipScreenshotTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ChipScreenshotTest.kt
@@ -129,6 +129,7 @@
     fun inputChip_lightTheme() {
         rule.setMaterialContent(lightColorScheme()) {
             InputChip(
+                selected = false,
                 onClick = {},
                 enabled = true,
                 modifier = Modifier.testTag(TestTag),
@@ -153,9 +154,38 @@
     }
 
     @Test
+    fun inputChip_selected_lightTheme() {
+        rule.setMaterialContent(lightColorScheme()) {
+            InputChip(
+                selected = true,
+                onClick = {},
+                enabled = true,
+                modifier = Modifier.testTag(TestTag),
+                label = { Text("Input chip") },
+                leadingIcon = {
+                    Icon(
+                        imageVector = Icons.Filled.Search,
+                        contentDescription = "Localized Description",
+                        modifier = Modifier.requiredSize(InputChipDefaults.IconSize)
+                    )
+                },
+                trailingIcon = {
+                    Icon(
+                        imageVector = Icons.Filled.Done,
+                        contentDescription = "Localized Description",
+                        modifier = Modifier.requiredSize(InputChipDefaults.IconSize)
+                    )
+                }
+            )
+        }
+        assertChipAgainstGolden("inputChip_selected_lightTheme")
+    }
+
+    @Test
     fun inputChip_withAvatar_lightTheme() {
         rule.setMaterialContent(lightColorScheme()) {
             InputChip(
+                selected = false,
                 onClick = {},
                 enabled = true,
                 modifier = Modifier.testTag(TestTag),
@@ -183,6 +213,7 @@
     fun inputChip_darkTheme() {
         rule.setMaterialContent(darkColorScheme()) {
             InputChip(
+                selected = false,
                 onClick = {},
                 enabled = true,
                 modifier = Modifier.testTag(TestTag),
@@ -207,9 +238,38 @@
     }
 
     @Test
-    fun inputChip_disabled_lightTheme() {
+    fun inputChip_selected_darkTheme() {
         rule.setMaterialContent(darkColorScheme()) {
             InputChip(
+                selected = true,
+                onClick = {},
+                enabled = true,
+                modifier = Modifier.testTag(TestTag),
+                label = { Text("Input chip") },
+                leadingIcon = {
+                    Icon(
+                        imageVector = Icons.Filled.Search,
+                        contentDescription = "Localized Description",
+                        modifier = Modifier.requiredSize(InputChipDefaults.IconSize)
+                    )
+                },
+                trailingIcon = {
+                    Icon(
+                        imageVector = Icons.Filled.Done,
+                        contentDescription = "Localized Description",
+                        modifier = Modifier.requiredSize(InputChipDefaults.IconSize)
+                    )
+                }
+            )
+        }
+        assertChipAgainstGolden("inputChip_selected_darkTheme")
+    }
+
+    @Test
+    fun inputChip_disabled_lightTheme() {
+        rule.setMaterialContent(lightColorScheme()) {
+            InputChip(
+                selected = false,
                 onClick = {},
                 enabled = false,
                 modifier = Modifier.testTag(TestTag),
@@ -220,9 +280,24 @@
     }
 
     @Test
+    fun inputChip_disabled_selected_lightTheme() {
+        rule.setMaterialContent(lightColorScheme()) {
+            InputChip(
+                selected = false,
+                onClick = {},
+                enabled = false,
+                modifier = Modifier.testTag(TestTag),
+                label = { Text("Input chip") }
+            )
+        }
+        assertChipAgainstGolden("inputChip_disabled_selected_lightTheme")
+    }
+
+    @Test
     fun inputChip_disabled_darkTheme() {
         rule.setMaterialContent(darkColorScheme()) {
             InputChip(
+                selected = false,
                 onClick = {},
                 enabled = false,
                 modifier = Modifier.testTag(TestTag),
@@ -233,6 +308,20 @@
     }
 
     @Test
+    fun inputChip_disabled_selected_darkTheme() {
+        rule.setMaterialContent(darkColorScheme()) {
+            InputChip(
+                selected = true,
+                onClick = {},
+                enabled = false,
+                modifier = Modifier.testTag(TestTag),
+                label = { Text("Input chip") }
+            )
+        }
+        assertChipAgainstGolden("inputChip_disabled_selected_darkTheme")
+    }
+
+    @Test
     fun filterChip_flat_selected_lightTheme() {
         rule.setMaterialContent(lightColorScheme()) {
             FilterChip(
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ChipTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ChipTest.kt
index 75f2ede..1a173e3 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ChipTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/ChipTest.kt
@@ -509,6 +509,7 @@
         rule.setMaterialContent(lightColorScheme()) {
             Box {
                 InputChip(
+                    selected = false,
                     onClick = {},
                     modifier = Modifier.testTag(TestChipTag),
                     label = { Text(TestChipTag) })
@@ -516,16 +517,55 @@
         }
 
         rule.onNodeWithTag(TestChipTag)
-            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
             .assertIsEnabled()
             .assertHasClickAction()
     }
 
     @Test
+    fun unselectedSemantics_inputChip() {
+        rule.setMaterialContent(lightColorScheme()) {
+            Box {
+                InputChip(
+                    selected = false,
+                    onClick = {},
+                    modifier = Modifier.testTag(TestChipTag),
+                    label = { Text(TestChipTag) })
+            }
+        }
+
+        rule.onNodeWithTag(TestChipTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
+            .assertIsEnabled()
+            .assertHasClickAction()
+            .assertIsNotSelected()
+    }
+
+    @Test
+    fun selectedSemantics_inputChip() {
+        rule.setMaterialContent(lightColorScheme()) {
+            Box {
+                InputChip(
+                    selected = true,
+                    onClick = {},
+                    modifier = Modifier.testTag(TestChipTag),
+                    label = { Text(TestChipTag) })
+            }
+        }
+
+        rule.onNodeWithTag(TestChipTag)
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
+            .assertIsEnabled()
+            .assertHasClickAction()
+            .assertIsSelected()
+    }
+
+    @Test
     fun disabledSemantics_inputChip() {
         rule.setMaterialContent(lightColorScheme()) {
             Box {
                 InputChip(
+                    selected = false,
                     modifier = Modifier.testTag(TestChipTag),
                     onClick = {},
                     label = { Text(TestChipTag) },
@@ -535,31 +575,31 @@
         }
 
         rule.onNodeWithTag(TestChipTag)
-            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Button))
+            .assert(SemanticsMatcher.expectValue(SemanticsProperties.Role, Role.Checkbox))
             .assertIsNotEnabled()
             .assertHasClickAction()
+            .assertIsNotSelected()
     }
 
     @Test
-    fun onClick_inputChip() {
-        var counter = 0
-        val onClick: () -> Unit = { ++counter }
-
+    fun toggle_inputChip() {
         rule.setMaterialContent(lightColorScheme()) {
+            val selected = remember { mutableStateOf(false) }
             Box {
                 InputChip(
-                    onClick = onClick,
+                    selected = selected.value,
+                    onClick = { selected.value = !selected.value },
                     modifier = Modifier.testTag(TestChipTag),
                     label = { Text("Test chip") })
             }
         }
 
         rule.onNodeWithTag(TestChipTag)
+            .assertIsNotSelected()
             .performClick()
-
-        rule.runOnIdle {
-            assertThat(counter).isEqualTo(1)
-        }
+            .assertIsSelected()
+            .performClick()
+            .assertIsNotSelected()
     }
 
     @Test
@@ -568,7 +608,7 @@
         // so lets skip it.
         Assume.assumeTrue(rule.density.fontScale <= 1f)
         rule.setMaterialContent(lightColorScheme()) {
-            InputChip(onClick = {}, label = { Text("Test chip") })
+            InputChip(selected = false, onClick = {}, label = { Text("Test chip") })
         }
 
         rule.onNode(hasClickAction())
@@ -580,6 +620,7 @@
         var chipCoordinates: LayoutCoordinates? = null
         rule.setMaterialContent(lightColorScheme()) {
             InputChip(
+                selected = false,
                 onClick = {},
                 modifier = Modifier.onGloballyPositioned { chipCoordinates = it },
                 label = {
@@ -607,6 +648,7 @@
         var chipCoordinates: LayoutCoordinates? = null
         rule.setMaterialContent(lightColorScheme()) {
             InputChip(
+                selected = false,
                 onClick = {},
                 modifier = Modifier.onGloballyPositioned { chipCoordinates = it },
                 label = {
@@ -642,6 +684,7 @@
         var chipCoordinates: LayoutCoordinates? = null
         rule.setMaterialContent(lightColorScheme()) {
             InputChip(
+                selected = false,
                 onClick = {},
                 modifier = Modifier.onGloballyPositioned { chipCoordinates = it },
                 label = {
@@ -674,17 +717,31 @@
 
     @Test
     fun labelContentColor_inputChip() {
-        var expectedLabelColor = Color.Unspecified
+        var selectedLabelColor = Color.Unspecified
+        var unselectedLabelColor = Color.Unspecified
         var contentColor = Color.Unspecified
         rule.setMaterialContent(lightColorScheme()) {
-            expectedLabelColor = InputChipTokens.LabelTextColor.toColor()
-            InputChip(onClick = {}, label = {
-                contentColor = LocalContentColor.current
-            })
+            val selected = remember { mutableStateOf(false) }
+            selectedLabelColor = InputChipTokens.SelectedLabelTextColor.toColor()
+            unselectedLabelColor = InputChipTokens.UnselectedLabelTextColor.toColor()
+            InputChip(
+                selected = selected.value,
+                onClick = { selected.value = !selected.value },
+                label = {
+                    contentColor = LocalContentColor.current
+                },
+                modifier = Modifier.testTag(TestChipTag)
+            )
         }
 
         rule.runOnIdle {
-            assertThat(contentColor).isEqualTo(expectedLabelColor)
+            assertThat(contentColor).isEqualTo(unselectedLabelColor)
+        }
+
+        rule.onNodeWithTag(TestChipTag).performClick()
+
+        rule.runOnIdle {
+            assertThat(contentColor).isEqualTo(selectedLabelColor)
         }
     }
 
@@ -932,12 +989,16 @@
                 },
                 label = {
                     Spacer(
-                        Modifier.requiredSize(10.dp).onGloballyPositioned {
-                            item1Bounds = it.boundsInRoot()
-                        }
+                        Modifier
+                            .requiredSize(10.dp)
+                            .onGloballyPositioned {
+                                item1Bounds = it.boundsInRoot()
+                            }
                     )
                     Spacer(
-                        Modifier.requiredWidth(10.dp).requiredHeight(5.dp)
+                        Modifier
+                            .requiredWidth(10.dp)
+                            .requiredHeight(5.dp)
                             .onGloballyPositioned {
                                 item2Bounds = it.boundsInRoot()
                             }
@@ -958,7 +1019,9 @@
         rule.setMaterialContent(lightColorScheme()) {
             Box(Modifier.fillMaxSize()) {
                 SuggestionChip(
-                    modifier = Modifier.align(Alignment.Center).testTag(TestChipTag)
+                    modifier = Modifier
+                        .align(Alignment.Center)
+                        .testTag(TestChipTag)
                         .requiredSize(10.dp),
                     onClick = { clicked = !clicked },
                     label = { Box(Modifier.size(10.dp)) }
diff --git a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/FloatingActionButtonTest.kt b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/FloatingActionButtonTest.kt
index 8262cf75..f999349 100644
--- a/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/FloatingActionButtonTest.kt
+++ b/compose/material3/material3/src/androidAndroidTest/kotlin/androidx/compose/material3/FloatingActionButtonTest.kt
@@ -425,6 +425,9 @@
                     iconBounds.center.x + iconBounds.width / 2 + halfPadding,
                     textBounds.center.x - textBounds.width / 2 - halfPadding
                 )
+                // Assert that text and icon have 12.dp padding between them.
+                assertThat(textBounds.left - iconBounds.right)
+                    .isEqualTo(12.dp.roundToPx().toFloat())
             }
         }
     }
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 5782d58..8f0d760 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
@@ -19,6 +19,7 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Favorite
+import androidx.compose.material3.tokens.NavigationBarTokens
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -59,7 +60,6 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import androidx.compose.material3.tokens.NavigationBarTokens
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
@@ -174,17 +174,20 @@
 
         rule.runOnIdleWithDensity {
             val totalWidth = parentCoords.size.width
+            val availableWidth =
+                totalWidth.toFloat() - (NavigationBarItemHorizontalPadding.toPx() * 3)
 
-            val expectedItemWidth = totalWidth / 4
-            val expectedItemHeight = NavigationBarTokens.ContainerHeight.roundToPx()
+            val expectedItemWidth = (availableWidth / 4)
+            val expectedItemHeight = NavigationBarTokens.ContainerHeight.toPx()
 
             Truth.assertThat(itemCoords.size).isEqualTo(4)
 
             itemCoords.forEach { (index, coord) ->
-                Truth.assertThat(coord.size.width).isEqualTo(expectedItemWidth)
-                Truth.assertThat(coord.size.height).isEqualTo(expectedItemHeight)
-                Truth.assertThat(coord.positionInWindow().x)
-                    .isEqualTo((expectedItemWidth * index).toFloat())
+                // Rounding differences for width can occur on smaller screens
+                Truth.assertThat(coord.size.width.toFloat()).isWithin(1f).of(expectedItemWidth)
+                Truth.assertThat(coord.size.height).isEqualTo(expectedItemHeight.toInt())
+                Truth.assertThat(coord.positionInWindow().x).isWithin(1f)
+                    .of((expectedItemWidth + NavigationBarItemHorizontalPadding.toPx()) * index)
             }
         }
     }
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 23fa0ed..c6d48e3 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
@@ -948,9 +948,12 @@
                     RangeSlider(
                         values = 0f..0.5f,
                         onValueChange = {},
-                        modifier = Modifier.testTag(tag).weight(1f).onGloballyPositioned {
-                            sliderBounds = it.boundsInParent()
-                        }
+                        modifier = Modifier
+                            .testTag(tag)
+                            .weight(1f)
+                            .onGloballyPositioned {
+                                sliderBounds = it.boundsInParent()
+                            }
                     )
                     Spacer(Modifier.requiredSize(100.toDp()))
                 }
@@ -1038,7 +1041,7 @@
             ProgressBarRangeInfo(
                 5f,
                 0f..10f,
-                3
+                1
             )
         )
 
@@ -1046,7 +1049,7 @@
             ProgressBarRangeInfo(
                 10f,
                 5f..20f,
-                3,
+                2,
             )
         )
 
@@ -1057,9 +1060,9 @@
             .performSemanticsAction(SemanticsActions.SetProgress) { it(15f) }
 
         rule.onAllNodes(isFocusable(), true)[0]
-            .assertRangeInfoEquals(ProgressBarRangeInfo(10f, 0f..15f, 3))
+            .assertRangeInfoEquals(ProgressBarRangeInfo(10f, 0f..15f, 2))
 
         rule.onAllNodes(isFocusable(), true)[1]
-            .assertRangeInfoEquals(ProgressBarRangeInfo(15f, 10f..20f, 3))
+            .assertRangeInfoEquals(ProgressBarRangeInfo(15f, 10f..20f, 1))
     }
 }
\ No newline at end of file
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
index ab9214a..d8c7fc1 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Chip.kt
@@ -79,8 +79,7 @@
  * Example of a flat AssistChip:
  * @sample androidx.compose.material3.samples.AssistChipSample
  *
- * @param onClick called when this chip is clicked. If `null`, then this chip will not be
- * interactable, unless something else handles its input events and updates its state.
+ * @param onClick called when this chip is clicked
  * @param label text label for this chip
  * @param modifier the [Modifier] to be applied to this chip
  * @param enabled controls the enabled state of this chip. When `false`, this component will not
@@ -124,13 +123,9 @@
     labelTextStyle = MaterialTheme.typography.fromToken(AssistChipTokens.LabelTextFont),
     labelColor = colors.labelColor(enabled).value,
     leadingIcon = leadingIcon,
-    avatar = null,
     trailingIcon = trailingIcon,
-    leadingIconColor = colors.leadingIconContentColor(enabled).value,
-    trailingIconColor = colors.trailingIconContentColor(enabled).value,
-    containerColor = colors.containerColor(enabled).value,
-    tonalElevation = elevation?.tonalElevation(enabled, interactionSource)?.value ?: 0.dp,
-    shadowElevation = elevation?.shadowElevation(enabled, interactionSource)?.value ?: 0.dp,
+    elevation = elevation,
+    colors = colors,
     minHeight = AssistChipDefaults.Height,
     paddingValues = AssistChipPadding,
     shape = shape,
@@ -157,8 +152,7 @@
  * Example of an elevated AssistChip with a trailing icon:
  * @sample androidx.compose.material3.samples.ElevatedAssistChipSample
  *
- * @param onClick called when this chip is clicked. If `null`, then this chip will not be
- * interactable, unless something else handles its input events and updates its state.
+ * @param onClick called when this chip is clicked
  * @param label text label for this chip
  * @param modifier the [Modifier] to be applied to this chip
  * @param enabled controls the enabled state of this chip. When `false`, this component will not
@@ -201,13 +195,9 @@
     labelTextStyle = MaterialTheme.typography.fromToken(AssistChipTokens.LabelTextFont),
     labelColor = colors.labelColor(enabled).value,
     leadingIcon = leadingIcon,
-    avatar = null,
     trailingIcon = trailingIcon,
-    leadingIconColor = colors.leadingIconContentColor(enabled).value,
-    trailingIconColor = colors.trailingIconContentColor(enabled).value,
-    containerColor = colors.containerColor(enabled).value,
-    tonalElevation = elevation?.tonalElevation(enabled, interactionSource)?.value ?: 0.dp,
-    shadowElevation = elevation?.shadowElevation(enabled, interactionSource)?.value ?: 0.dp,
+    elevation = elevation,
+    colors = colors,
     minHeight = AssistChipDefaults.Height,
     paddingValues = AssistChipPadding,
     shape = shape,
@@ -240,8 +230,7 @@
  * @sample androidx.compose.material3.samples.FilterChipWithLeadingIconSample
  *
  * @param selected whether this chip is selected or not
- * @param onClick called when this chip is clicked. If `null`, then this chip will not be
- * interactable, unless something else handles its input events and updates its state.
+ * @param onClick called when this chip is clicked
  * @param label text label for this chip
  * @param modifier the [Modifier] to be applied to this chip
  * @param enabled controls the enabled state of this chip. When `false`, this component will not
@@ -289,6 +278,7 @@
     label = label,
     labelTextStyle = MaterialTheme.typography.fromToken(FilterChipTokens.LabelTextFont),
     leadingIcon = if (selected) selectedIcon else leadingIcon,
+    avatar = null,
     trailingIcon = trailingIcon,
     elevation = elevation,
     colors = colors,
@@ -321,8 +311,7 @@
  * @sample androidx.compose.material3.samples.ElevatedFilterChipSample
  *
  * @param selected whether this chip is selected or not
- * @param onClick called when this chip is clicked. If `null`, then this chip will not be
- * interactable, unless something else handles its input events and updates its state.
+ * @param onClick called when this chip is clicked
  * @param label text label for this chip
  * @param modifier the [Modifier] to be applied to this chip
  * @param enabled controls the enabled state of this chip. When `false`, this component will not
@@ -370,6 +359,7 @@
     label = label,
     labelTextStyle = MaterialTheme.typography.fromToken(FilterChipTokens.LabelTextFont),
     leadingIcon = if (selected) selectedIcon else leadingIcon,
+    avatar = null,
     trailingIcon = trailingIcon,
     elevation = elevation,
     colors = colors,
@@ -406,8 +396,8 @@
  * Alternatively, use Accompanist's [Flow Layouts](https://google.github.io/accompanist/flowlayout/)
  * to wrap chips to a new line.
  *
- * @param onClick called when this chip is clicked. If `null`, then this chip will not be
- * interactable, unless something else handles its input events and updates its state.
+ * @param selected whether this chip is selected or not
+ * @param onClick called when this chip is clicked
  * @param label text label for this chip
  * @param modifier the [Modifier] to be applied to this chip
  * @param enabled controls the enabled state of this chip. When `false`, this component will not
@@ -433,6 +423,7 @@
 @ExperimentalMaterial3Api
 @Composable
 fun InputChip(
+    selected: Boolean,
     onClick: () -> Unit,
     label: @Composable () -> Unit,
     modifier: Modifier = Modifier,
@@ -441,10 +432,10 @@
     avatar: @Composable (() -> Unit)? = null,
     trailingIcon: @Composable (() -> Unit)? = null,
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    elevation: ChipElevation? = InputChipDefaults.inputChipElevation(),
+    elevation: SelectableChipElevation? = InputChipDefaults.inputChipElevation(),
     shape: Shape = InputChipTokens.ContainerShape.toShape(),
-    border: ChipBorder? = InputChipDefaults.inputChipBorder(),
-    colors: ChipColors = InputChipDefaults.inputChipColors()
+    border: SelectableChipBorder? = InputChipDefaults.inputChipBorder(),
+    colors: SelectableChipColors = InputChipDefaults.inputChipColors()
 ) {
     // If given, place the avatar in an InputChipTokens.AvatarShape shape before passing it into the
     // Chip function.
@@ -465,21 +456,18 @@
             }
         }
     }
-    Chip(
+    SelectableChip(
+        selected = selected,
         modifier = modifier,
         onClick = onClick,
         enabled = enabled,
         label = label,
         labelTextStyle = MaterialTheme.typography.fromToken(InputChipTokens.LabelTextFont),
-        labelColor = colors.labelColor(enabled).value,
         leadingIcon = leadingIcon,
         avatar = shapedAvatar,
         trailingIcon = trailingIcon,
-        leadingIconColor = colors.leadingIconContentColor(enabled).value,
-        trailingIconColor = colors.trailingIconContentColor(enabled).value,
-        containerColor = colors.containerColor(enabled).value,
-        tonalElevation = elevation?.tonalElevation(enabled, interactionSource)?.value ?: 0.dp,
-        shadowElevation = elevation?.shadowElevation(enabled, interactionSource)?.value ?: 0.dp,
+        elevation = elevation,
+        colors = colors,
         minHeight = InputChipDefaults.Height,
         paddingValues = inputChipPadding(
             hasAvatar = shapedAvatar != null,
@@ -487,7 +475,7 @@
             hasTrailingIcon = trailingIcon != null
         ),
         shape = shape,
-        border = border?.borderStroke(enabled)?.value,
+        border = border?.borderStroke(enabled, selected)?.value,
         interactionSource = interactionSource
     )
 }
@@ -510,8 +498,7 @@
  * Example of a flat SuggestionChip with a trailing icon:
  * @sample androidx.compose.material3.samples.SuggestionChipSample
  *
- * @param onClick called when this chip is clicked. If `null`, then this chip will not be
- * interactable, unless something else handles its input events and updates its state.
+ * @param onClick called when this chip is clicked
  * @param label text label for this chip
  * @param modifier the [Modifier] to be applied to this chip
  * @param enabled controls the enabled state of this chip. When `false`, this component will not
@@ -553,13 +540,9 @@
     labelTextStyle = MaterialTheme.typography.fromToken(SuggestionChipTokens.LabelTextFont),
     labelColor = colors.labelColor(enabled).value,
     leadingIcon = icon,
-    avatar = null,
     trailingIcon = null,
-    leadingIconColor = colors.leadingIconContentColor(enabled).value,
-    trailingIconColor = colors.trailingIconContentColor(enabled).value,
-    containerColor = colors.containerColor(enabled).value,
-    tonalElevation = elevation?.tonalElevation(enabled, interactionSource)?.value ?: 0.dp,
-    shadowElevation = elevation?.shadowElevation(enabled, interactionSource)?.value ?: 0.dp,
+    elevation = elevation,
+    colors = colors,
     minHeight = SuggestionChipDefaults.Height,
     paddingValues = SuggestionChipPadding,
     shape = shape,
@@ -585,8 +568,7 @@
  * Example of an elevated SuggestionChip with a trailing icon:
  * @sample androidx.compose.material3.samples.ElevatedSuggestionChipSample
  *
- * @param onClick called when this chip is clicked. If `null`, then this chip will not be
- * interactable, unless something else handles its input events and updates its state.
+ * @param onClick called when this chip is clicked
  * @param label text label for this chip
  * @param modifier the [Modifier] to be applied to this chip
  * @param enabled controls the enabled state of this chip. When `false`, this component will not
@@ -627,13 +609,9 @@
     labelTextStyle = MaterialTheme.typography.fromToken(SuggestionChipTokens.LabelTextFont),
     labelColor = colors.labelColor(enabled).value,
     leadingIcon = icon,
-    avatar = null,
     trailingIcon = null,
-    leadingIconColor = colors.leadingIconContentColor(enabled).value,
-    trailingIconColor = colors.trailingIconContentColor(enabled).value,
-    containerColor = colors.containerColor(enabled).value,
-    tonalElevation = elevation?.tonalElevation(enabled, interactionSource)?.value ?: 0.dp,
-    shadowElevation = elevation?.shadowElevation(enabled, interactionSource)?.value ?: 0.dp,
+    elevation = elevation,
+    colors = colors,
     minHeight = SuggestionChipDefaults.Height,
     paddingValues = SuggestionChipPadding,
     shape = shape,
@@ -870,7 +848,7 @@
      * @param labelColor the label color of this chip when enabled
      * @param leadingIconContentColor the color of this chip's start icon when enabled
      * @param trailingIconContentColor the color of this chip's end icon when enabled
-     * @param disabledContainerColor the container  color of this chip when not enabled
+     * @param disabledContainerColor the container color of this chip when not enabled
      * @param disabledLabelColor the label color of this chip when not enabled
      * @param disabledLeadingIconContentColor the color of this chip's start icon when not enabled
      * @param disabledTrailingIconContentColor the color of this chip's end icon when not enabled
@@ -974,7 +952,7 @@
      * @param labelColor the label color of this chip when enabled
      * @param leadingIconContentColor the color of this chip's start icon when enabled
      * @param trailingIconContentColor the color of this chip's end icon when enabled
-     * @param disabledContainerColor the container  color of this chip when not enabled
+     * @param disabledContainerColor the container color of this chip when not enabled
      * @param disabledLabelColor the label color of this chip when not enabled
      * @param disabledLeadingIconContentColor the color of this chip's start icon when not enabled
      * @param disabledTrailingIconContentColor the color of this chip's end icon when not enabled
@@ -1074,6 +1052,8 @@
      * @param disabledLeadingIconColor the color of this chip's start icon when not enabled
      * @param disabledTrailingIconColor the color of this chip's end icon when not enabled
      * @param selectedContainerColor the container color of this chip when selected
+     * @param disabledSelectedContainerColor the container color of this chip when not enabled and
+     * selected
      * @param selectedLabelColor the label color of this chip when selected
      * @param selectedLeadingIconColor the color of this chip's start icon when selected
      * @param selectedTrailingIconColor the color of this chip's end icon when selected
@@ -1090,6 +1070,9 @@
             .copy(alpha = FilterChipTokens.DisabledIconOpacity),
         disabledTrailingIconColor: Color = disabledLeadingIconColor,
         selectedContainerColor: Color = FilterChipTokens.FlatSelectedContainerColor.toColor(),
+        disabledSelectedContainerColor: Color =
+            FilterChipTokens.FlatDisabledSelectedContainerColor.toColor()
+                .copy(alpha = FilterChipTokens.FlatDisabledSelectedContainerOpacity),
         selectedLabelColor: Color = FilterChipTokens.SelectedLabelTextColor.toColor(),
         selectedLeadingIconColor: Color = FilterChipTokens.SelectedIconColor.toColor(),
         selectedTrailingIconColor: Color = selectedLeadingIconColor
@@ -1103,14 +1086,15 @@
         disabledLeadingIconColor = disabledLeadingIconColor,
         disabledTrailingIconColor = disabledTrailingIconColor,
         selectedContainerColor = selectedContainerColor,
+        disabledSelectedContainerColor = disabledSelectedContainerColor,
         selectedLabelColor = selectedLabelColor,
         selectedLeadingIconColor = selectedLeadingIconColor,
         selectedTrailingIconColor = selectedTrailingIconColor
     )
 
     /**
-     * Creates a [ChipElevation] that will animate between the provided values according to the
-     * Material specification for a flat [FilterChip].
+     * Creates a [SelectableChipElevation] that will animate between the provided values according
+     * to the Material specification for a flat [FilterChip].
      *
      * @param defaultElevation the elevation used when the [FilterChip] is has no other
      * [Interaction]s
@@ -1149,7 +1133,8 @@
     }
 
     /**
-     * Creates a [ChipBorder] that represents the default border used in a flat [FilterChip].
+     * Creates a [SelectableChipBorder] that represents the default border used in a flat
+     * [FilterChip].
      *
      * @param borderColor the border color of this chip when enabled and not selected
      * @param selectedBorderColor the border color of this chip when enabled and selected
@@ -1200,7 +1185,9 @@
      * @param disabledLabelColor the label color of this chip when not enabled
      * @param disabledLeadingIconColor the color of this chip's start icon when not enabled
      * @param disabledTrailingIconColor the color of this chip's end icon when not enabled
-     * @param selectedContainerColor the container  color of this chip when selected
+     * @param selectedContainerColor the container color of this chip when selected
+     * @param disabledSelectedContainerColor the container color of this chip when not enabled and
+     * selected
      * @param selectedLabelColor the label color of this chip when selected
      * @param selectedLeadingIconColor the color of this chip's start icon when selected
      * @param selectedTrailingIconColor the color of this chip's end icon when selected
@@ -1218,6 +1205,7 @@
             .copy(alpha = FilterChipTokens.DisabledIconOpacity),
         disabledTrailingIconColor: Color = disabledLeadingIconColor,
         selectedContainerColor: Color = FilterChipTokens.ElevatedSelectedContainerColor.toColor(),
+        disabledSelectedContainerColor: Color = disabledContainerColor,
         selectedLabelColor: Color = FilterChipTokens.SelectedLabelTextColor.toColor(),
         selectedLeadingIconColor: Color = FilterChipTokens.SelectedIconColor.toColor(),
         selectedTrailingIconColor: Color = selectedLeadingIconColor
@@ -1231,14 +1219,15 @@
         disabledLeadingIconColor = disabledLeadingIconColor,
         disabledTrailingIconColor = disabledTrailingIconColor,
         selectedContainerColor = selectedContainerColor,
+        disabledSelectedContainerColor = disabledSelectedContainerColor,
         selectedLabelColor = selectedLabelColor,
         selectedLeadingIconColor = selectedLeadingIconColor,
         selectedTrailingIconColor = selectedTrailingIconColor
     )
 
     /**
-     * Creates a [ChipElevation] that will animate between the provided values according to the
-     * Material specification for an elevated [FilterChip].
+     * Creates a [SelectableChipElevation] that will animate between the provided values according
+     * to the Material specification for an elevated [FilterChip].
      *
      * @param defaultElevation the elevation used when the chip is has no other
      * [Interaction]s
@@ -1299,49 +1288,65 @@
     val AvatarSize = InputChipTokens.AvatarSize
 
     /**
-     * Creates a [ChipColors] that represents the default container, label, and icon colors used in
-     * an [InputChip].
+     * Creates a [SelectableChipColors] that represents the default container, label, and icon
+     * colors used in an [InputChip].
      *
      * @param containerColor the container color of this chip when enabled
      * @param labelColor the label color of this chip when enabled
-     * @param leadingIconContentColor the color of this chip's start icon when enabled
-     * @param trailingIconContentColor the color of this chip's end icon when enabled
+     * @param leadingIconColor the color of this chip's start icon when enabled
+     * @param trailingIconColor the color of this chip's start end icon when enabled
      * @param disabledContainerColor the container color of this chip when not enabled
      * @param disabledLabelColor the label color of this chip when not enabled
-     * @param disabledLeadingIconContentColor the color of this chip's start icon when not enabled
-     * @param disabledTrailingIconContentColor the color of this chip's end icon when not enabled
+     * @param disabledLeadingIconColor the color of this chip's start icon when not enabled
+     * @param disabledTrailingIconColor the color of this chip's end icon when not enabled
+     * @param selectedContainerColor the container color of this chip when selected
+     * @param disabledSelectedContainerColor the container color of this chip when not enabled and
+     * selected
+     * @param selectedLabelColor the label color of this chip when selected
+     * @param selectedLeadingIconColor the color of this chip's start icon when selected
+     * @param selectedTrailingIconColor the color of this chip's end icon when selected
      */
     @Composable
     fun inputChipColors(
         containerColor: Color = Color.Transparent,
-        labelColor: Color = InputChipTokens.LabelTextColor.toColor(),
-        leadingIconContentColor: Color = InputChipTokens.LeadingIconColor.toColor(),
-        trailingIconContentColor: Color = InputChipTokens.TrailingIconColor.toColor(),
+        labelColor: Color = InputChipTokens.UnselectedLabelTextColor.toColor(),
+        leadingIconColor: Color = InputChipTokens.UnselectedLeadingIconColor.toColor(),
+        trailingIconColor: Color = InputChipTokens.UnselectedTrailingIconColor.toColor(),
         disabledContainerColor: Color = Color.Transparent,
         disabledLabelColor: Color = InputChipTokens.DisabledLabelTextColor.toColor()
             .copy(alpha = InputChipTokens.DisabledLabelTextOpacity),
-        disabledLeadingIconContentColor: Color =
-            InputChipTokens.DisabledLeadingIconColor.toColor()
-                .copy(alpha = InputChipTokens.DisabledLeadingIconOpacity),
-        disabledTrailingIconContentColor: Color =
-            InputChipTokens.DisabledTrailingIconColor.toColor()
-                .copy(alpha = InputChipTokens.DisabledTrailingIconOpacity),
-    ): ChipColors = DefaultChipColors(
+        disabledLeadingIconColor: Color = InputChipTokens.DisabledLeadingIconColor.toColor()
+            .copy(alpha = InputChipTokens.DisabledLeadingIconOpacity),
+        disabledTrailingIconColor: Color = InputChipTokens.DisabledTrailingIconColor.toColor()
+            .copy(alpha = InputChipTokens.DisabledTrailingIconOpacity),
+        selectedContainerColor: Color = InputChipTokens.SelectedContainerColor.toColor(),
+        disabledSelectedContainerColor: Color =
+            InputChipTokens.DisabledSelectedContainerColor.toColor()
+                .copy(alpha = InputChipTokens.DisabledSelectedContainerOpacity),
+        selectedLabelColor: Color = InputChipTokens.SelectedLabelTextColor.toColor(),
+        selectedLeadingIconColor: Color = InputChipTokens.SelectedLeadingIconColor.toColor(),
+        selectedTrailingIconColor: Color = InputChipTokens.SelectedTrailingIconColor.toColor()
+    ): SelectableChipColors = DefaultSelectableChipColors(
         containerColor = containerColor,
         labelColor = labelColor,
-        leadingIconContentColor = leadingIconContentColor,
-        trailingIconContentColor = trailingIconContentColor,
+        leadingIconColor = leadingIconColor,
+        trailingIconColor = trailingIconColor,
         disabledContainerColor = disabledContainerColor,
         disabledLabelColor = disabledLabelColor,
-        disabledLeadingIconContentColor = disabledLeadingIconContentColor,
-        disabledTrailingIconContentColor = disabledTrailingIconContentColor
+        disabledLeadingIconColor = disabledLeadingIconColor,
+        disabledTrailingIconColor = disabledTrailingIconColor,
+        selectedContainerColor = selectedContainerColor,
+        disabledSelectedContainerColor = disabledSelectedContainerColor,
+        selectedLabelColor = selectedLabelColor,
+        selectedLeadingIconColor = selectedLeadingIconColor,
+        selectedTrailingIconColor = selectedTrailingIconColor
     )
 
     /**
-     * Creates a [ChipElevation] that will animate between the provided values according to the
-     * Material specification for an [InputChip].
+     * Creates a [SelectableChipElevation] that will animate between the provided values according
+     * to the Material specification for an [InputChip].
      *
-     * @param defaultElevation the elevation used when the [InputChip] is has no other
+     * @param defaultElevation the elevation used when the [FilterChip] is has no other
      * [Interaction]s
      * @param pressedElevation the elevation used when the chip is pressed
      * @param focusedElevation the elevation used when the chip is focused
@@ -1357,7 +1362,7 @@
         hoveredElevation: Dp = defaultElevation,
         draggedElevation: Dp = InputChipTokens.DraggedContainerElevation,
         disabledElevation: Dp = defaultElevation
-    ): ChipElevation {
+    ): SelectableChipElevation {
         return remember(
             defaultElevation,
             pressedElevation,
@@ -1366,7 +1371,7 @@
             draggedElevation,
             disabledElevation
         ) {
-            DefaultChipElevation(
+            DefaultSelectableChipElevation(
                 defaultElevation = defaultElevation,
                 pressedElevation = pressedElevation,
                 focusedElevation = focusedElevation,
@@ -1378,28 +1383,42 @@
     }
 
     /**
-     * Creates a [ChipBorder] that represents the default border used in an [InputChip].
+     * Creates a [SelectableChipBorder] that represents the default border used in an [InputChip].
      *
-     * @param borderColor the border color of this chip when enabled
-     * @param disabledBorderColor the border color of this chip when not enabled
-     * @param borderWidth the border stroke width of this chip
+     * @param borderColor the border color of this chip when enabled and not selected
+     * @param selectedBorderColor the border color of this chip when enabled and selected
+     * @param disabledBorderColor the border color of this chip when not enabled and not
+     * selected
+     * @param disabledSelectedBorderColor the border color of this chip when not enabled
+     * but selected
+     * @param borderWidth the border stroke width of this chip when not selected
+     * @param selectedBorderWidth the border stroke width of this chip when selected
      */
     @Composable
     fun inputChipBorder(
-        borderColor: Color = InputChipTokens.OutlineColor.toColor(),
-        disabledBorderColor: Color = InputChipTokens.DisabledOutlineColor.toColor()
-            .copy(alpha = InputChipTokens.DisabledOutlineOpacity),
-        borderWidth: Dp = InputChipTokens.OutlineWidth,
-    ): ChipBorder {
+        borderColor: Color = InputChipTokens.UnselectedOutlineColor.toColor(),
+        selectedBorderColor: Color = Color.Transparent,
+        disabledBorderColor: Color = InputChipTokens.DisabledUnselectedOutlineColor.toColor()
+            .copy(alpha = InputChipTokens.DisabledUnselectedOutlineOpacity),
+        disabledSelectedBorderColor: Color = Color.Transparent,
+        borderWidth: Dp = InputChipTokens.UnselectedOutlineWidth,
+        selectedBorderWidth: Dp = InputChipTokens.SelectedOutlineWidth,
+    ): SelectableChipBorder {
         return remember(
             borderColor,
+            selectedBorderColor,
             disabledBorderColor,
-            borderWidth
+            disabledSelectedBorderColor,
+            borderWidth,
+            selectedBorderWidth
         ) {
-            DefaultChipBorder(
+            DefaultSelectableChipBorder(
                 borderColor = borderColor,
+                selectedBorderColor = selectedBorderColor,
                 disabledBorderColor = disabledBorderColor,
-                borderWidth = borderWidth
+                disabledSelectedBorderColor = disabledSelectedBorderColor,
+                borderWidth = borderWidth,
+                selectedBorderWidth = selectedBorderWidth
             )
         }
     }
@@ -1608,13 +1627,9 @@
     labelTextStyle: TextStyle,
     labelColor: Color,
     leadingIcon: @Composable (() -> Unit)?,
-    avatar: @Composable (() -> Unit)?,
     trailingIcon: @Composable (() -> Unit)?,
-    leadingIconColor: Color,
-    trailingIconColor: Color,
-    containerColor: Color,
-    tonalElevation: Dp,
-    shadowElevation: Dp,
+    elevation: ChipElevation?,
+    colors: ChipColors,
     minHeight: Dp,
     paddingValues: PaddingValues,
     shape: Shape,
@@ -1626,9 +1641,9 @@
         modifier = modifier,
         enabled = enabled,
         shape = shape,
-        color = containerColor,
-        tonalElevation = tonalElevation,
-        shadowElevation = shadowElevation,
+        color = colors.containerColor(enabled).value,
+        tonalElevation = elevation?.tonalElevation(enabled, interactionSource)?.value ?: 0.dp,
+        shadowElevation = elevation?.shadowElevation(enabled, interactionSource)?.value ?: 0.dp,
         border = border,
         interactionSource = interactionSource,
     ) {
@@ -1637,10 +1652,10 @@
             labelTextStyle = labelTextStyle,
             labelColor = labelColor,
             leadingIcon = leadingIcon,
-            avatar = avatar,
+            avatar = null,
             trailingIcon = trailingIcon,
-            leadingIconColor = leadingIconColor,
-            trailingIconColor = trailingIconColor,
+            leadingIconColor = colors.leadingIconContentColor(enabled).value,
+            trailingIconColor = colors.trailingIconContentColor(enabled).value,
             minHeight = minHeight,
             paddingValues = paddingValues
         )
@@ -1657,6 +1672,7 @@
     label: @Composable () -> Unit,
     labelTextStyle: TextStyle,
     leadingIcon: @Composable (() -> Unit)?,
+    avatar: @Composable (() -> Unit)?,
     trailingIcon: @Composable (() -> Unit)?,
     elevation: SelectableChipElevation?,
     colors: SelectableChipColors,
@@ -1685,7 +1701,7 @@
             label = label,
             labelTextStyle = labelTextStyle,
             leadingIcon = leadingIcon,
-            avatar = null,
+            avatar = avatar,
             labelColor = colors.labelColor(enabled, selected).value,
             trailingIcon = trailingIcon,
             leadingIconColor = colors.leadingIconContentColor(enabled, selected).value,
@@ -1714,7 +1730,9 @@
         LocalTextStyle provides labelTextStyle
     ) {
         Row(
-            Modifier.defaultMinSize(minHeight = minHeight).padding(paddingValues),
+            Modifier
+                .defaultMinSize(minHeight = minHeight)
+                .padding(paddingValues),
             horizontalArrangement = Arrangement.Start,
             verticalAlignment = Alignment.CenterVertically
         ) {
@@ -2048,6 +2066,7 @@
     private val disabledLeadingIconColor: Color,
     private val disabledTrailingIconColor: Color,
     private val selectedContainerColor: Color,
+    private val disabledSelectedContainerColor: Color,
     private val selectedLabelColor: Color,
     private val selectedLeadingIconColor: Color,
     private val selectedTrailingIconColor: Color
@@ -2056,7 +2075,7 @@
     @Composable
     override fun containerColor(enabled: Boolean, selected: Boolean): State<Color> {
         val target = when {
-            !enabled -> disabledContainerColor
+            !enabled -> if (selected) disabledSelectedContainerColor else disabledContainerColor
             !selected -> containerColor
             else -> selectedContainerColor
         }
@@ -2108,6 +2127,7 @@
         if (disabledLeadingIconColor != other.disabledLeadingIconColor) return false
         if (disabledTrailingIconColor != other.disabledTrailingIconColor) return false
         if (selectedContainerColor != other.selectedContainerColor) return false
+        if (disabledSelectedContainerColor != other.disabledSelectedContainerColor) return false
         if (selectedLabelColor != other.selectedLabelColor) return false
         if (selectedLeadingIconColor != other.selectedLeadingIconColor) return false
         if (selectedTrailingIconColor != other.selectedTrailingIconColor) return false
@@ -2125,6 +2145,7 @@
         result = 31 * result + disabledLeadingIconColor.hashCode()
         result = 31 * result + disabledTrailingIconColor.hashCode()
         result = 31 * result + selectedContainerColor.hashCode()
+        result = 31 * result + disabledSelectedContainerColor.hashCode()
         result = 31 * result + selectedLabelColor.hashCode()
         result = 31 * result + selectedLeadingIconColor.hashCode()
         result = 31 * result + selectedTrailingIconColor.hashCode()
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/MappedInteractionSource.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/MappedInteractionSource.kt
new file mode 100644
index 0000000..3004270
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/MappedInteractionSource.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.compose.material3
+
+import androidx.compose.foundation.interaction.InteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
+import androidx.compose.ui.geometry.Offset
+import kotlinx.coroutines.flow.map
+
+/**
+ * Adapts an [InteractionSource] from one component to another by mapping any interactions by a
+ * given offset. Namely used for the pill indicator in [NavigationBarItem] and [NavigationRailItem].
+ */
+internal class MappedInteractionSource(
+    underlyingInteractionSource: InteractionSource,
+    private val delta: Offset
+) : InteractionSource {
+    private val mappedPresses =
+        mutableMapOf<PressInteraction.Press, PressInteraction.Press>()
+
+    override val interactions = underlyingInteractionSource.interactions.map { interaction ->
+        when (interaction) {
+            is PressInteraction.Press -> {
+                val mappedPress = mapPress(interaction)
+                mappedPresses[interaction] = mappedPress
+                mappedPress
+            }
+            is PressInteraction.Cancel -> {
+                val mappedPress = mappedPresses.remove(interaction.press)
+                if (mappedPress == null) {
+                    interaction
+                } else {
+                    PressInteraction.Cancel(mappedPress)
+                }
+            }
+            is PressInteraction.Release -> {
+                val mappedPress = mappedPresses.remove(interaction.press)
+                if (mappedPress == null) {
+                    interaction
+                } else {
+                    PressInteraction.Release(mappedPress)
+                }
+            }
+            else -> interaction
+        }
+    }
+
+    private fun mapPress(press: PressInteraction.Press): PressInteraction.Press =
+        PressInteraction.Press(press.pressPosition - delta)
+}
\ No newline at end of file
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 5fc7b6f..85fc603 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
@@ -20,6 +20,7 @@
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.background
+import androidx.compose.foundation.indication
 import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Arrangement
@@ -38,10 +39,14 @@
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.alpha
+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
@@ -49,6 +54,8 @@
 import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.layout.Placeable
 import androidx.compose.ui.layout.layoutId
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Dp
@@ -99,7 +106,7 @@
     ) {
         Row(
             modifier = Modifier.fillMaxWidth().height(NavigationBarHeight).selectableGroup(),
-            horizontalArrangement = Arrangement.SpaceBetween,
+            horizontalArrangement = Arrangement.spacedBy(NavigationBarItemHorizontalPadding),
             content = content
         )
     }
@@ -166,6 +173,8 @@
         }
     }
 
+    var itemWidth by remember { mutableStateOf(0) }
+
     Box(
         modifier
             .selectable(
@@ -174,9 +183,12 @@
                 enabled = enabled,
                 role = Role.Tab,
                 interactionSource = interactionSource,
-                indication = rememberRipple(),
+                indication = null,
             )
-            .weight(1f),
+            .weight(1f)
+            .onSizeChanged {
+                itemWidth = it.width
+            },
         contentAlignment = Alignment.Center
     ) {
         val animationProgress: Float by animateFloatAsState(
@@ -184,6 +196,30 @@
             animationSpec = tween(ItemAnimationDurationMillis)
         )
 
+        // The entire item is selectable, but only the indicator pill shows the ripple. To achieve
+        // this, we re-map the coordinates of the item's InteractionSource into the coordinates of
+        // the indicator.
+        val deltaOffset: Offset
+        with(LocalDensity.current) {
+            val indicatorWidth = NavigationBarTokens.ActiveIndicatorWidth.roundToPx()
+            deltaOffset = Offset(
+                (itemWidth - indicatorWidth).toFloat() / 2,
+                IndicatorVerticalOffset.toPx()
+            )
+        }
+        val offsetInteractionSource = remember(interactionSource, deltaOffset) {
+            MappedInteractionSource(interactionSource, deltaOffset)
+        }
+
+        // The indicator has a width-expansion animation which interferes with the timing of the
+        // ripple, which is why they are separate composables
+        val indicatorRipple = @Composable {
+            Box(
+                Modifier.layoutId(IndicatorRippleLayoutIdTag)
+                    .clip(NavigationBarTokens.ActiveIndicatorShape.toShape())
+                    .indication(offsetInteractionSource, rememberRipple())
+            )
+        }
         val indicator = @Composable {
             Box(
                 Modifier.layoutId(IndicatorLayoutIdTag)
@@ -195,6 +231,7 @@
         }
 
         NavigationBarItemBaselineLayout(
+            indicatorRipple = indicatorRipple,
             indicator = indicator,
             icon = styledIcon,
             label = styledLabel,
@@ -297,6 +334,7 @@
 /**
  * Base layout for a [NavigationBarItem].
  *
+ * @param indicatorRipple indicator ripple for this item when it is selected
  * @param indicator indicator for this item when it is selected
  * @param icon icon for this item
  * @param label text label for this item
@@ -308,6 +346,7 @@
  */
 @Composable
 private fun NavigationBarItemBaselineLayout(
+    indicatorRipple: @Composable () -> Unit,
     indicator: @Composable () -> Unit,
     icon: @Composable () -> Unit,
     label: @Composable (() -> Unit)?,
@@ -315,6 +354,7 @@
     animationProgress: Float,
 ) {
     Layout({
+        indicatorRipple()
         if (animationProgress > 0) {
             indicator()
         }
@@ -325,7 +365,7 @@
             Box(
                 Modifier.layoutId(LabelLayoutIdTag)
                     .alpha(if (alwaysShowLabel) 1f else animationProgress)
-                    .padding(horizontal = NavigationBarItemHorizontalPadding)
+                    .padding(horizontal = NavigationBarItemHorizontalPadding / 2)
             ) { label() }
         }
     }) { measurables, constraints ->
@@ -335,6 +375,15 @@
         val totalIndicatorWidth = iconPlaceable.width + (IndicatorHorizontalPadding * 2).roundToPx()
         val animatedIndicatorWidth = (totalIndicatorWidth * animationProgress).roundToInt()
         val indicatorHeight = iconPlaceable.height + (IndicatorVerticalPadding * 2).roundToPx()
+        val indicatorRipplePlaceable =
+            measurables
+                .first { it.layoutId == IndicatorRippleLayoutIdTag }
+                .measure(
+                    Constraints.fixed(
+                        width = totalIndicatorWidth,
+                        height = indicatorHeight
+                    )
+                )
         val indicatorPlaceable =
             measurables
                 .firstOrNull { it.layoutId == IndicatorLayoutIdTag }
@@ -357,11 +406,12 @@
             }
 
         if (label == null) {
-            placeIcon(iconPlaceable, indicatorPlaceable, constraints)
+            placeIcon(iconPlaceable, indicatorRipplePlaceable, indicatorPlaceable, constraints)
         } else {
             placeLabelAndIcon(
                 labelPlaceable!!,
                 iconPlaceable,
+                indicatorRipplePlaceable,
                 indicatorPlaceable,
                 constraints,
                 alwaysShowLabel,
@@ -372,11 +422,11 @@
 }
 
 /**
- * Places the provided [iconPlaceable], and possibly [indicatorPlaceable] if it exists, in the
- * center of the provided [constraints].
+ * Places the provided [Placeable]s in the center of the provided [constraints].
  */
 private fun MeasureScope.placeIcon(
     iconPlaceable: Placeable,
+    indicatorRipplePlaceable: Placeable,
     indicatorPlaceable: Placeable?,
     constraints: Constraints
 ): MeasureResult {
@@ -386,6 +436,9 @@
     val iconX = (width - iconPlaceable.width) / 2
     val iconY = (height - iconPlaceable.height) / 2
 
+    val rippleX = (width - indicatorRipplePlaceable.width) / 2
+    val rippleY = (height - indicatorRipplePlaceable.height) / 2
+
     return layout(width, height) {
         indicatorPlaceable?.let {
             val indicatorX = (width - it.width) / 2
@@ -393,12 +446,13 @@
             it.placeRelative(indicatorX, indicatorY)
         }
         iconPlaceable.placeRelative(iconX, iconY)
+        indicatorRipplePlaceable.placeRelative(rippleX, rippleY)
     }
 }
 
 /**
- * Places the provided [labelPlaceable], [iconPlaceable], and [indicatorPlaceable] in the correct
- * position, depending on [alwaysShowLabel] and [animationProgress].
+ * Places the provided [Placeable]s in the correct position, depending on [alwaysShowLabel] and
+ * [animationProgress].
  *
  * When [alwaysShowLabel] is true, the positions do not move. The [iconPlaceable] will be placed
  * near the top of the item and the [labelPlaceable] will be placed near the bottom, according to
@@ -413,11 +467,12 @@
  * When [animationProgress] is animating between these values, [iconPlaceable] and [labelPlaceable]
  * will be placed at a corresponding interpolated position.
  *
- * [indicatorPlaceable] will always be placed in such a way that it shares the same center as
- * [iconPlaceable].
+ * [indicatorRipplePlaceable] and [indicatorPlaceable] will always be placed in such a way that to
+ * share the same center as [iconPlaceable].
  *
  * @param labelPlaceable text label placeable inside this item
  * @param iconPlaceable icon placeable inside this item
+ * @param indicatorRipplePlaceable indicator ripple placeable inside this item
  * @param indicatorPlaceable indicator placeable inside this item, if it exists
  * @param constraints constraints of the item
  * @param alwaysShowLabel whether to always show the label for this item. If true, icon and label
@@ -430,6 +485,7 @@
 private fun MeasureScope.placeLabelAndIcon(
     labelPlaceable: Placeable,
     iconPlaceable: Placeable,
+    indicatorRipplePlaceable: Placeable,
     indicatorPlaceable: Placeable?,
     constraints: Constraints,
     alwaysShowLabel: Boolean,
@@ -458,6 +514,9 @@
     val labelX = (containerWidth - labelPlaceable.width) / 2
     val iconX = (containerWidth - iconPlaceable.width) / 2
 
+    val rippleX = (containerWidth - indicatorRipplePlaceable.width) / 2
+    val rippleY = selectedIconY - IndicatorVerticalPadding.roundToPx()
+
     return layout(containerWidth, height) {
         indicatorPlaceable?.let {
             val indicatorX = (containerWidth - it.width) / 2
@@ -468,9 +527,12 @@
             labelPlaceable.placeRelative(labelX, labelY + offset)
         }
         iconPlaceable.placeRelative(iconX, selectedIconY + offset)
+        indicatorRipplePlaceable.placeRelative(rippleX, rippleY + offset)
     }
 }
 
+private const val IndicatorRippleLayoutIdTag: String = "indicatorRipple"
+
 private const val IndicatorLayoutIdTag: String = "indicator"
 
 private const val IconLayoutIdTag: String = "icon"
@@ -481,7 +543,8 @@
 
 private const val ItemAnimationDurationMillis: Int = 100
 
-private val NavigationBarItemHorizontalPadding: Dp = 4.dp
+/*@VisibleForTesting*/
+internal val NavigationBarItemHorizontalPadding: Dp = 8.dp
 
 /*@VisibleForTesting*/
 internal val NavigationBarItemVerticalPadding: Dp = 16.dp
@@ -490,4 +553,6 @@
     (NavigationBarTokens.ActiveIndicatorWidth - NavigationBarTokens.IconSize) / 2
 
 private val IndicatorVerticalPadding: Dp =
-    (NavigationBarTokens.ActiveIndicatorHeight - NavigationBarTokens.IconSize) / 2
\ No newline at end of file
+    (NavigationBarTokens.ActiveIndicatorHeight - NavigationBarTokens.IconSize) / 2
+
+private val IndicatorVerticalOffset: Dp = 12.dp
\ No newline at end of file
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationRail.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationRail.kt
index af24fb2..8616b23 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationRail.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationRail.kt
@@ -20,6 +20,7 @@
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.background
+import androidx.compose.foundation.indication
 import androidx.compose.foundation.interaction.Interaction
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Arrangement
@@ -45,12 +46,15 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.layout.MeasureResult
 import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.layout.Placeable
 import androidx.compose.ui.layout.layoutId
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Dp
@@ -179,7 +183,7 @@
                 enabled = enabled,
                 role = Role.Tab,
                 interactionSource = interactionSource,
-                indication = rememberRipple(),
+                indication = null,
             )
             .size(width = NavigationRailItemWidth, height = NavigationRailItemHeight),
         contentAlignment = Alignment.Center
@@ -189,21 +193,46 @@
             animationSpec = tween(ItemAnimationDurationMillis)
         )
 
+        // The entire item is selectable, but only the indicator pill shows the ripple. To achieve
+        // this, we re-map the coordinates of the item's InteractionSource into the coordinates of
+        // the indicator.
+        val deltaOffset: Offset
+        with(LocalDensity.current) {
+            val itemWidth = NavigationRailItemWidth.roundToPx()
+            val indicatorWidth = NavigationRailTokens.ActiveIndicatorWidth.roundToPx()
+            deltaOffset = Offset((itemWidth - indicatorWidth).toFloat() / 2, 0f)
+        }
+        val offsetInteractionSource = remember(interactionSource, deltaOffset) {
+            MappedInteractionSource(interactionSource, deltaOffset)
+        }
+
+        val indicatorShape = if (label != null) {
+            NavigationRailTokens.ActiveIndicatorShape.toShape()
+        } else {
+            NavigationRailTokens.NoLabelActiveIndicatorShape.toShape()
+        }
+
+        // The indicator has a width-expansion animation which interferes with the timing of the
+        // ripple, which is why they are separate composables
+        val indicatorRipple = @Composable {
+            Box(
+                Modifier.layoutId(IndicatorRippleLayoutIdTag)
+                    .clip(indicatorShape)
+                    .indication(offsetInteractionSource, rememberRipple())
+            )
+        }
         val indicator = @Composable {
             Box(
                 Modifier.layoutId(IndicatorLayoutIdTag)
                     .background(
                         color = colors.indicatorColor.copy(alpha = animationProgress),
-                        shape = if (label != null) {
-                            NavigationRailTokens.ActiveIndicatorShape.toShape()
-                        } else {
-                            NavigationRailTokens.NoLabelActiveIndicatorShape.toShape()
-                        }
+                        shape = indicatorShape
                     )
             )
         }
 
         NavigationRailItemBaselineLayout(
+            indicatorRipple = indicatorRipple,
             indicator = indicator,
             icon = styledIcon,
             label = styledLabel,
@@ -306,6 +335,7 @@
 /**
  * Base layout for a [NavigationRailItem].
  *
+ * @param indicatorRipple indicator ripple for this item when it is selected
  * @param indicator indicator for this item when it is selected
  * @param icon icon for this item
  * @param label text label for this item
@@ -317,6 +347,7 @@
  */
 @Composable
 private fun NavigationRailItemBaselineLayout(
+    indicatorRipple: @Composable () -> Unit,
     indicator: @Composable () -> Unit,
     icon: @Composable () -> Unit,
     label: @Composable (() -> Unit)?,
@@ -324,6 +355,7 @@
     animationProgress: Float,
 ) {
     Layout({
+        indicatorRipple()
         if (animationProgress > 0) {
             indicator()
         }
@@ -349,6 +381,15 @@
         }
         val indicatorHeight = iconPlaceable.height + (indicatorVerticalPadding * 2).roundToPx()
 
+        val indicatorRipplePlaceable =
+            measurables
+                .first { it.layoutId == IndicatorRippleLayoutIdTag }
+                .measure(
+                    Constraints.fixed(
+                        width = totalIndicatorWidth,
+                        height = indicatorHeight
+                    )
+                )
         val indicatorPlaceable =
             measurables
                 .firstOrNull { it.layoutId == IndicatorLayoutIdTag }
@@ -371,11 +412,12 @@
             }
 
         if (label == null) {
-            placeIcon(iconPlaceable, indicatorPlaceable, constraints)
+            placeIcon(iconPlaceable, indicatorRipplePlaceable, indicatorPlaceable, constraints)
         } else {
             placeLabelAndIcon(
                 labelPlaceable!!,
                 iconPlaceable,
+                indicatorRipplePlaceable,
                 indicatorPlaceable,
                 constraints,
                 alwaysShowLabel,
@@ -386,11 +428,11 @@
 }
 
 /**
- * Places the provided [iconPlaceable], and possibly [indicatorPlaceable] if it exists, in the
- * center of the provided [constraints].
+ * Places the provided [Placeable]s in the center of the provided [constraints].
  */
 private fun MeasureScope.placeIcon(
     iconPlaceable: Placeable,
+    indicatorRipplePlaceable: Placeable,
     indicatorPlaceable: Placeable?,
     constraints: Constraints,
 ): MeasureResult {
@@ -400,6 +442,9 @@
     val iconX = (width - iconPlaceable.width) / 2
     val iconY = (height - iconPlaceable.height) / 2
 
+    val rippleX = (width - indicatorRipplePlaceable.width) / 2
+    val rippleY = (height - indicatorRipplePlaceable.height) / 2
+
     return layout(width, height) {
         indicatorPlaceable?.let {
             val indicatorX = (width - it.width) / 2
@@ -407,12 +452,13 @@
             it.placeRelative(indicatorX, indicatorY)
         }
         iconPlaceable.placeRelative(iconX, iconY)
+        indicatorRipplePlaceable.placeRelative(rippleX, rippleY)
     }
 }
 
 /**
- * Places the provided [labelPlaceable], [iconPlaceable], and [indicatorPlaceable] in the correct
- * position, depending on [alwaysShowLabel] and [animationProgress].
+ * Places the provided [Placeable]s in the correct position, depending on [alwaysShowLabel] and
+ * [animationProgress].
  *
  * When [alwaysShowLabel] is true, the positions do not move. The [iconPlaceable] will be placed
  * near the top of the item and the [labelPlaceable] will be placed near the bottom, according to
@@ -427,11 +473,12 @@
  * When [animationProgress] is animating between these values, [iconPlaceable] and [labelPlaceable]
  * will be placed at a corresponding interpolated position.
  *
- * [indicatorPlaceable] will always be placed in such a way that it shares the same center as
- * [iconPlaceable].
+ * [indicatorRipplePlaceable] and [indicatorPlaceable] will always be placed in such a way that to
+ * share the same center as [iconPlaceable].
  *
  * @param labelPlaceable text label placeable inside this item
  * @param iconPlaceable icon placeable inside this item
+ * @param indicatorRipplePlaceable indicator ripple placeable inside this item
  * @param indicatorPlaceable indicator placeable inside this item, if it exists
  * @param constraints constraints of the item
  * @param alwaysShowLabel whether to always show the label for this item. If true, icon and label
@@ -444,6 +491,7 @@
 private fun MeasureScope.placeLabelAndIcon(
     labelPlaceable: Placeable,
     iconPlaceable: Placeable,
+    indicatorRipplePlaceable: Placeable,
     indicatorPlaceable: Placeable?,
     constraints: Constraints,
     alwaysShowLabel: Boolean,
@@ -469,6 +517,8 @@
     val width = constraints.maxWidth
     val labelX = (width - labelPlaceable.width) / 2
     val iconX = (width - iconPlaceable.width) / 2
+    val rippleX = (width - indicatorRipplePlaceable.width) / 2
+    val rippleY = selectedIconY - IndicatorVerticalPaddingWithLabel.roundToPx()
 
     return layout(width, height) {
         indicatorPlaceable?.let {
@@ -480,9 +530,12 @@
             labelPlaceable.placeRelative(labelX, labelY + offset)
         }
         iconPlaceable.placeRelative(iconX, selectedIconY + offset)
+        indicatorRipplePlaceable.placeRelative(rippleX, rippleY + offset)
     }
 }
 
+private const val IndicatorRippleLayoutIdTag: String = "indicatorRipple"
+
 private const val IndicatorLayoutIdTag: String = "indicator"
 
 private const val IconLayoutIdTag: String = "icon"
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 4a82ae9..34750c6 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
@@ -94,6 +94,7 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.util.lerp
 import kotlin.math.abs
+import kotlin.math.floor
 import kotlin.math.max
 import kotlin.math.min
 import kotlinx.coroutines.CancellationException
@@ -168,7 +169,7 @@
                 minWidth = SliderTokens.HandleWidth,
                 minHeight = SliderTokens.HandleHeight
             )
-            .sliderSemantics(value, tickFractions, enabled, onValueChange, valueRange, steps)
+            .sliderSemantics(value, enabled, onValueChange, valueRange, steps)
             .focusable(enabled, interactionSource)
     ) {
         val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
@@ -401,27 +402,27 @@
             gestureEndAction,
             onDrag,
         )
-
         // The positions of the thumbs are dependant on each other.
         val coercedStart = values.start.coerceIn(valueRange.start, values.endInclusive)
         val coercedEnd = values.endInclusive.coerceIn(values.start, valueRange.endInclusive)
         val fractionStart = calcFraction(valueRange.start, valueRange.endInclusive, coercedStart)
         val fractionEnd = calcFraction(valueRange.start, valueRange.endInclusive, coercedEnd)
+        val startSteps = floor(steps * fractionEnd).toInt()
+        val endSteps = floor(steps * (1f - fractionStart)).toInt()
+
         val startThumbSemantics = Modifier.sliderSemantics(
             coercedStart,
-            tickFractions,
             enabled,
             { value -> onValueChangeState.value.invoke(value..coercedEnd) },
             valueRange.start..coercedEnd,
-            steps
+            startSteps
         )
         val endThumbSemantics = Modifier.sliderSemantics(
             coercedEnd,
-            tickFractions,
             enabled,
             { value -> onValueChangeState.value.invoke(coercedStart..value) },
             coercedStart..valueRange.endInclusive,
-            steps
+            endSteps
         )
 
         RangeSliderImpl(
@@ -467,7 +468,9 @@
         val offsetStart = widthDp * positionFractionStart
         val offsetEnd = widthDp * positionFractionEnd
         Track(
-            Modifier.align(Alignment.CenterStart).fillMaxSize(),
+            Modifier
+                .align(Alignment.CenterStart)
+                .fillMaxSize(),
             colors,
             enabled,
             positionFractionStart,
@@ -661,7 +664,10 @@
     enabled: Boolean,
     thumbSize: DpSize
 ) {
-    Box(Modifier.padding(start = offset).align(Alignment.CenterStart)) {
+    Box(
+        Modifier
+            .padding(start = offset)
+            .align(Alignment.CenterStart)) {
         val interactions = remember { mutableStateListOf<Interaction>() }
         LaunchedEffect(interactionSource) {
             interactionSource.interactions.collect { interaction ->
@@ -825,7 +831,6 @@
 
 private fun Modifier.sliderSemantics(
     value: Float,
-    tickFractions: List<Float>,
     enabled: Boolean,
     onValueChange: (Float) -> Unit,
     valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
@@ -836,20 +841,26 @@
         if (!enabled) disabled()
         setProgress(
             action = { targetValue ->
-                val newValue = targetValue.coerceIn(valueRange.start, valueRange.endInclusive)
+                var newValue = targetValue.coerceIn(valueRange.start, valueRange.endInclusive)
+                val originalVal = newValue
                 val resolvedValue = if (steps > 0) {
-                    tickFractions
-                        .map {
-                            lerp(
-                                valueRange.start,
-                                valueRange.endInclusive,
-                                it
-                            )
+                    var distance: Float = newValue
+                    for (i in 0..steps + 1) {
+                        val stepValue = lerp(
+                            valueRange.start,
+                            valueRange.endInclusive,
+                            i.toFloat() / (steps + 1)
+                        )
+                        if (abs(stepValue - originalVal) <= distance) {
+                            distance = abs(stepValue - originalVal)
+                            newValue = stepValue
                         }
-                        .minByOrNull { abs(it - newValue) } ?: newValue
+                    }
+                    newValue
                 } else {
                     newValue
                 }
+
                 // This is to keep it consistent with AbsSeekbar.java: return false if no
                 // change from current.
                 if (resolvedValue == coerced) {
@@ -1129,7 +1140,8 @@
 private val SliderHeight = 48.dp
 private val SliderMinWidth = 144.dp // TODO: clarify min width
 private val DefaultSliderConstraints =
-    Modifier.widthIn(min = SliderMinWidth)
+    Modifier
+        .widthIn(min = SliderMinWidth)
         .heightIn(max = SliderHeight)
 
 private val SliderToTickAnimation = TweenSpec<Float>(durationMillis = 100)
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/InputChipTokens.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/InputChipTokens.kt
index 5163010..98af8af 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/InputChipTokens.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens/InputChipTokens.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-// VERSION: v0_92
+// VERSION: v0_101
 // GENERATED CODE - DO NOT MODIFY BY HAND
 
 package androidx.compose.material3.tokens
@@ -26,35 +26,54 @@
     val ContainerShape = ShapeKeyTokens.CornerSmall
     val DisabledLabelTextColor = ColorSchemeKeyTokens.OnSurface
     const val DisabledLabelTextOpacity = 0.38f
-    val DisabledOutlineColor = ColorSchemeKeyTokens.OnSurface
-    const val DisabledOutlineOpacity = 0.12f
+    val DisabledSelectedContainerColor = ColorSchemeKeyTokens.OnSurface
+    const val DisabledSelectedContainerOpacity = 0.12f
+    val DisabledUnselectedOutlineColor = ColorSchemeKeyTokens.OnSurface
+    const val DisabledUnselectedOutlineOpacity = 0.12f
     val DraggedContainerElevation = ElevationTokens.Level4
-    val DraggedLabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
-    val FocusLabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
-    val FocusOutlineColor = ColorSchemeKeyTokens.OnSurfaceVariant
-    val HoverLabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
-    val LabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
     val LabelTextFont = TypographyKeyTokens.LabelLarge
-    val OutlineColor = ColorSchemeKeyTokens.Outline
-    val OutlineWidth = 1.0.dp
-    val PressedLabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val SelectedContainerColor = ColorSchemeKeyTokens.SecondaryContainer
+    val SelectedDraggedLabelTextColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedFocusLabelTextColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedHoverLabelTextColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedLabelTextColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedOutlineWidth = 0.0.dp
+    val SelectedPressedLabelTextColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val UnselectedDraggedLabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedFocusLabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedFocusOutlineColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedHoverLabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedLabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedOutlineColor = ColorSchemeKeyTokens.Outline
+    val UnselectedOutlineWidth = 1.0.dp
+    val UnselectedPressedLabelTextColor = ColorSchemeKeyTokens.OnSurfaceVariant
     val AvatarShape = ShapeKeyTokens.CornerFull
     val AvatarSize = 24.0.dp
     const val DisabledAvatarOpacity = 0.38f
     val DisabledLeadingIconColor = ColorSchemeKeyTokens.OnSurface
     const val DisabledLeadingIconOpacity = 0.38f
-    val DraggedLeadingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
-    val FocusLeadingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
-    val HoverLeadingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
-    val LeadingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
     val LeadingIconSize = 18.0.dp
-    val PressedLeadingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val SelectedDraggedLeadingIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedFocusLeadingIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedHoverLeadingIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedLeadingIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedPressedLeadingIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val UnselectedDraggedLeadingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedFocusLeadingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedHoverLeadingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedLeadingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedPressedLeadingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
     val DisabledTrailingIconColor = ColorSchemeKeyTokens.OnSurface
     const val DisabledTrailingIconOpacity = 0.38f
-    val DraggedTrailingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
-    val FocusTrailingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
-    val HoverTrailingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
-    val PressedTrailingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
-    val TrailingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val SelectedDraggedTrailingIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedFocusTrailingIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedHoverTrailingIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedPressedTrailingIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
+    val SelectedTrailingIconColor = ColorSchemeKeyTokens.OnSecondaryContainer
     val TrailingIconSize = 18.0.dp
+    val UnselectedDraggedTrailingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedFocusTrailingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedHoverTrailingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedPressedTrailingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
+    val UnselectedTrailingIconColor = ColorSchemeKeyTokens.OnSurfaceVariant
 }
diff --git a/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
index b8a6cfd..25e96a6 100644
--- a/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
+++ b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
@@ -24,16 +24,16 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.snapshots.Snapshot
 import androidx.compose.runtime.snapshots.SnapshotStateObserver
-import androidx.test.filters.LargeTest
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
 import kotlin.math.pow
 import kotlin.math.roundToInt
 import kotlin.random.Random
+import org.junit.After
 import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
@@ -116,6 +116,36 @@
     }
 
     @Test
+    fun deeplyNestedModelObservations() {
+        assumeTrue(Build.VERSION.SDK_INT != 29)
+        runOnUiThread {
+            val list = mutableListOf<Any>()
+            repeat(100) {
+                list += nodes[random.nextInt(ScopeCount)]
+            }
+
+            fun observeRecursive(index: Int) {
+                if (index == 100) return
+                val node = list[index]
+                stateObserver.observeReads(node, doNothing) {
+                    observeForNode(node)
+                    observeRecursive(index + 1)
+                }
+            }
+
+            benchmarkRule.measureRepeated {
+                runWithTimingDisabled {
+                    random = Random(0)
+                    nodes.forEach { node ->
+                        stateObserver.clear(node)
+                    }
+                }
+                observeRecursive(0)
+            }
+        }
+    }
+
+    @Test
     fun modelClear() {
         assumeTrue(Build.VERSION.SDK_INT != 29)
         runOnUiThread {
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt
index 0811a24..5b960ea 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/IdentityArrayMap.kt
@@ -106,15 +106,23 @@
         return false
     }
 
-    @Suppress("UNCHECKED_CAST")
-    inline fun removeValueIf(block: (value: Value) -> Boolean) {
+    fun clear() {
+        size = 0
+        keys.fill(null)
+        values.fill(null)
+    }
+
+    inline fun removeIf(block: (key: Key, value: Value) -> Boolean) {
         var current = 0
         for (index in 0 until size) {
+            @Suppress("UNCHECKED_CAST")
+            val key = keys[index] as Key
+            @Suppress("UNCHECKED_CAST")
             val value = values[index] as Value
-            if (!block(value)) {
+            if (!block(key, value)) {
                 if (current != index) {
-                    keys[current] = keys[index]
-                    values[current] = value
+                    keys[current] = key
+                    values[current] = values[index]
                 }
                 current++
             }
@@ -128,6 +136,10 @@
         }
     }
 
+    inline fun removeValueIf(block: (value: Value) -> Boolean) {
+        removeIf { _, value -> block(value) }
+    }
+
     inline fun forEach(block: (key: Key, value: Value) -> Unit) {
         for (index in 0 until size) {
             @Suppress("UNCHECKED_CAST")
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
index 516644a..890dd67 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
@@ -17,30 +17,30 @@
 package androidx.compose.runtime.snapshots
 
 import androidx.compose.runtime.TestOnly
+import androidx.compose.runtime.collection.IdentityArrayMap
+import androidx.compose.runtime.collection.IdentityArraySet
 import androidx.compose.runtime.collection.IdentityScopeMap
 import androidx.compose.runtime.collection.mutableVectorOf
-import androidx.compose.runtime.synchronized
 
+/**
+ * Helper class to efficiently observe snapshot state reads. See [observeReads] for more details.
+ *
+ * NOTE: This class is not thread-safe, so implementations should not reuse observer between
+ * different threads to avoid race conditions.
+ */
 @Suppress("NotCloseable") // we can't implement AutoCloseable from commonMain
 class SnapshotStateObserver(private val onChangedExecutor: (callback: () -> Unit) -> Unit) {
     private val applyObserver: (Set<Any>, Snapshot) -> Unit = { applied, _ ->
         var hasValues = false
 
-        synchronized(applyMaps) {
-            applyMaps.forEach { applyMap ->
-                val invalidated = applyMap.invalidated
-                val map = applyMap.map
-                for (value in applied) {
-                    map.forEachScopeOf(value) { scope ->
-                        invalidated += scope
-                        hasValues = true
-                    }
-                }
-            }
+        forEachScopeMap { scopeMap ->
+            hasValues = scopeMap.recordInvalidation(applied) || hasValues
         }
         if (hasValues) {
             onChangedExecutor {
-                callOnChanged()
+                forEachScopeMap { scopeMap ->
+                    scopeMap.notifyInvalidatedScopes()
+                }
             }
         }
     }
@@ -50,17 +50,29 @@
      */
     private val readObserver: (Any) -> Unit = { state ->
         if (!isPaused) {
-            synchronized(applyMaps) {
-                currentMap!!.addValue(state)
+            synchronized(observedScopeMaps) {
+                currentMap!!.recordRead(state)
             }
         }
     }
 
     /**
-     * List of all [ApplyMap]s. When [observeReads] is called, there will be a [ApplyMap]
-     * associated with its `onChanged` callback in this list. The list only grows.
+     * List of all [ObservedScopeMap]s. When [observeReads] is called, there will be a
+     * [ObservedScopeMap] associated with its [ObservedScopeMap.onChanged] callback in this list.
+     * The list only grows.
      */
-    private val applyMaps = mutableVectorOf<ApplyMap<*>>()
+    private val observedScopeMaps = mutableVectorOf<ObservedScopeMap>()
+
+    /**
+     * Helper for synchronized iteration over [observedScopeMaps]. All observed reads should
+     * happen on the same thread, but snapshots can be applied on a different thread, requiring
+     * synchronization.
+     */
+    private inline fun forEachScopeMap(block: (ObservedScopeMap) -> Unit) {
+        synchronized(observedScopeMaps) {
+            observedScopeMaps.forEach(block)
+        }
+    }
 
     /**
      * Method to call when unsubscribing from the apply observer.
@@ -68,50 +80,53 @@
     private var applyUnsubscribe: ObserverHandle? = null
 
     /**
-     * `true` when [withNoObservations] is called and read observations should no
-     * longer be considered invalidations for the `onCommit` callback.
+     * `true` when [withNoObservations] is called and read observations should not
+     * be considered invalidations for the current scope.
      */
     private var isPaused = false
 
     /**
-     * The [ApplyMap] that should be added to when a model is read during [observeReads].
+     * The [ObservedScopeMap] that should be added to when a model is read during [observeReads].
      */
-    private var currentMap: ApplyMap<*>? = null
+    private var currentMap: ObservedScopeMap? = null
 
     /**
      * Executes [block], observing state object reads during its execution.
      *
      * The [scope] and [onValueChangedForScope] are associated with any values that are read so
-     * that when those values change, [onValueChangedForScope] can be called with the [scope]
+     * that when those values change, [onValueChangedForScope] will be called with the [scope]
      * parameter.
      *
-     * Observation for [scope] will be paused when a new [observeReads] call is made or when
-     * [withNoObservations] is called.
+     * Observation can be paused with [Snapshot.withoutReadObservation].
      *
-     * Any previous observation with the given [scope] and [onValueChangedForScope] will be
-     * cleared when the [onValueChangedForScope] is called for [scope]. The
-     * [onValueChangedForScope] should trigger a new [observeReads] call to resubscribe to
-     * changes. They may also be cleared using [clearIf] or [clear].
+     * @param scope value associated with the observed scope.
+     * @param onValueChangedForScope is called with the [scope] when value read within [block]
+     * has been changed. For repeated observations, it is more performant to pass the same instance
+     * of the callback, as [observedScopeMaps] grows with each new callback instance.
+     * @param block to observe reads within.
      */
     fun <T : Any> observeReads(scope: T, onValueChangedForScope: (T) -> Unit, block: () -> Unit) {
-        val oldMap = currentMap
-        val oldPaused = isPaused
-        val applyMap = synchronized(applyMaps) {
+        val scopeMap = synchronized(observedScopeMaps) {
             ensureMap(onValueChangedForScope).also {
-                it.map.removeScope(scope)
+                it.clearScopeObservations(scope)
             }
         }
-        val oldScope = applyMap.currentScope
 
-        applyMap.currentScope = scope
-        currentMap = applyMap
-        isPaused = false
+        val oldPaused = isPaused
+        val oldMap = currentMap
+        val oldScope = scopeMap.currentScope
 
-        Snapshot.observe(readObserver, null, block)
+        try {
+            isPaused = false
+            currentMap = scopeMap
+            scopeMap.currentScope = scope
 
-        currentMap = oldMap
-        applyMap.currentScope = oldScope
-        isPaused = oldPaused
+            Snapshot.observe(readObserver, null, block)
+        } finally {
+            scopeMap.currentScope = oldScope
+            currentMap = oldMap
+            isPaused = oldPaused
+        }
     }
 
     /**
@@ -136,28 +151,22 @@
     }
 
     /**
-     * Clears all model read observations for a given [scope]. This clears values for all
-     * `onCommit` methods passed in [observeReads].
+     * Clears all state read observations for a given [scope]. This clears values for all
+     * `onValueChangedForScope` callbacks passed in [observeReads].
      */
     fun clear(scope: Any) {
-        synchronized(applyMaps) {
-            applyMaps.forEach { commitMap ->
-                commitMap.map.removeValueIf {
-                    it === scope
-                }
-            }
+        forEachScopeMap {
+            it.clearScopeObservations(scope)
         }
     }
 
     /**
-     * Remove observations using [predicate] to identify scope scopes to be removed. This is
+     * Remove observations using [predicate] to identify scopes to be removed. This is
      * used when a scope is no longer in the hierarchy and should not receive any callbacks.
      */
     fun clearIf(predicate: (scope: Any) -> Boolean) {
-        synchronized(applyMaps) {
-            applyMaps.forEach { applyMap ->
-                applyMap.map.removeValueIf(predicate)
-            }
+        forEachScopeMap { scopeMap ->
+            scopeMap.removeScopeIf(predicate)
         }
     }
 
@@ -188,79 +197,114 @@
      * Remove all observations.
      */
     fun clear() {
-        synchronized(applyMaps) {
-            applyMaps.forEach { applyMap ->
-                applyMap.map.clear()
-            }
+        forEachScopeMap { scopeMap ->
+            scopeMap.clear()
         }
     }
 
     /**
-     * Calls the `onChanged` callback for the given scopes.
-     */
-    private fun callOnChanged() {
-        applyMaps.forEach { applyMap ->
-            val scopes = applyMap.invalidated
-            if (scopes.isNotEmpty()) {
-                applyMap.callOnChanged(scopes)
-                scopes.clear()
-            }
-        }
-    }
-
-    /**
-     * Returns the [ApplyMap] within [applyMaps] associated with [onChanged] or a newly-
+     * Returns the [ObservedScopeMap] within [observedScopeMaps] associated with [onChanged] or a newly-
      * inserted one if it doesn't exist.
      *
      * Must be called inside a synchronized block.
      */
-    private fun <T : Any> ensureMap(onChanged: (T) -> Unit): ApplyMap<T> {
-        val index = applyMaps.indexOfFirst { it.onChanged === onChanged }
-        if (index == -1) {
-            val commitMap = ApplyMap(onChanged)
-            applyMaps += commitMap
-            return commitMap
+    @Suppress("UNCHECKED_CAST")
+    private fun <T : Any> ensureMap(onChanged: (T) -> Unit): ObservedScopeMap {
+        val scopeMap = observedScopeMaps.firstOrNull { it.onChanged === onChanged }
+        if (scopeMap == null) {
+            val map = ObservedScopeMap(onChanged as ((Any) -> Unit))
+            observedScopeMaps += map
+            return map
         }
-        @Suppress("UNCHECKED_CAST")
-        return applyMaps[index] as ApplyMap<T>
+        return scopeMap
     }
 
     /**
-     * Used to tie an [onChanged] to its scope by type. This works around some difficulties in
-     * unchecked casts with kotlin.
+     * Connects observed values to scopes for each [onChanged] callback.
      */
     @Suppress("UNCHECKED_CAST")
-    private class ApplyMap<T : Any>(val onChanged: (T) -> Unit) {
+    private class ObservedScopeMap(val onChanged: (Any) -> Unit) {
         /**
-         * Map (key = model, value = scope). These are the models that have been
-         * read during the scope's [SnapshotStateObserver.observeReads].
+         * Currently observed scope.
          */
-        val map = IdentityScopeMap<T>()
+        var currentScope: Any? = null
 
         /**
-         * Scopes that were invalidated. This and cleared during the [applyObserver] call.
+         * Values that have been read during the scope's [SnapshotStateObserver.observeReads].
          */
-        val invalidated = hashSetOf<Any>()
+        private val valueToScopes = IdentityScopeMap<Any>()
 
         /**
-         * Current scope that adds to [map] will use.
+         * Reverse index (scope -> values) for faster scope invalidation.
          */
-        var currentScope: T? = null
+        private val scopeToValues: IdentityArrayMap<Any, IdentityArraySet<Any>> =
+            IdentityArrayMap()
 
         /**
-         * Adds [value]/[currentScope] to the [map].
+         * Scopes that were invalidated during previous apply step.
          */
-        fun addValue(value: Any) {
-            map.add(value, currentScope!!)
+        private val invalidated = hashSetOf<Any>()
+
+        /**
+         * Record that [value] was read in [currentScope].
+         */
+        fun recordRead(value: Any) {
+            val scope = currentScope!!
+            valueToScopes.add(value, scope)
+            val recordedValues = scopeToValues[scope]
+                ?: IdentityArraySet<Any>().also { scopeToValues[scope] = it }
+
+            recordedValues.add(value)
         }
 
         /**
-         * Calls the `onCommit` callback for scopes affected by the given committed values.
+         * Clear observations for [scope].
          */
-        fun callOnChanged(scopes: Collection<Any>) {
-            scopes.forEach { scope ->
-                onChanged(scope as T)
+        fun clearScopeObservations(scope: Any) {
+            val recordedValues = scopeToValues[scope] ?: return
+            recordedValues.forEach {
+                valueToScopes.remove(it, scope)
             }
+            scopeToValues.remove(scope)
+        }
+
+        /**
+         * Remove observations in scopes matching [predicate].
+         */
+        inline fun removeScopeIf(predicate: (scope: Any) -> Boolean) {
+            valueToScopes.removeValueIf(predicate)
+            scopeToValues.removeIf { scope, _ -> predicate(scope) }
+        }
+
+        /**
+         * Clear all observations.
+         */
+        fun clear() {
+            valueToScopes.clear()
+            scopeToValues.clear()
+        }
+
+        /**
+         * Record scope invalidation for given set of values.
+         * @return whether any scopes observe changed values
+         */
+        fun recordInvalidation(changes: Set<Any>): Boolean {
+            var hasValues = false
+            for (value in changes) {
+                valueToScopes.forEachScopeOf(value) { scope ->
+                    invalidated += scope
+                    hasValues = true
+                }
+            }
+            return hasValues
+        }
+
+        /**
+         * Call [onChanged] for previously invalidated scopes.
+         */
+        fun notifyInvalidatedScopes() {
+            invalidated.forEach(onChanged)
+            invalidated.clear()
         }
     }
 }
diff --git a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/collection/IdentityArrayMapTests.kt b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/collection/IdentityArrayMapTests.kt
index f615fb9..e369aa4 100644
--- a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/collection/IdentityArrayMapTests.kt
+++ b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/collection/IdentityArrayMapTests.kt
@@ -72,6 +72,24 @@
     }
 
     @Test
+    fun canRemoveKeys() {
+        val map = IdentityArrayMap<Key, Int>()
+        repeat(keys.size) {
+            map[keys[it]] = it
+        }
+        map.removeIf { key, _ -> key.value % 2 == 0 }
+        assertEquals(keys.size / 2, map.size)
+        for (i in 1 until keys.size step 2) {
+            assertEquals(i, map[keys[i]], "map key $i")
+        }
+        for (i in 0 until keys.size step 2) {
+            assertEquals(null, map[keys[i]], "map key $i")
+        }
+        map.removeIf { _, _ -> true }
+        assertEquals(0, map.size, "map is not empty after removing everything")
+    }
+
+    @Test
     fun canForEachKeysAndValues() {
         val map = IdentityArrayMap<Key, String>()
         repeat(100) {
@@ -120,4 +138,15 @@
         }
         assertTrue(map.isEmpty())
     }
+
+    @Test
+    fun canClear() {
+        val map = IdentityArrayMap<Key, String>()
+        repeat(16) {
+            map[keys[it]] = it.toString()
+        }
+        map.clear()
+        assertTrue(map.isEmpty())
+        assertEquals(0, map.size, "map size should be 0 after calling clear")
+    }
 }
\ No newline at end of file
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 16abe0a..ca406ac 100644
--- a/compose/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-text/api/public_plus_experimental_current.txt
@@ -234,7 +234,7 @@
   }
 
   @androidx.compose.runtime.Immutable public final class ParagraphStyle {
-    ctor @androidx.compose.ui.text.ExperimentalTextApi public ParagraphStyle(optional androidx.compose.ui.text.style.TextAlign? textAlign, optional androidx.compose.ui.text.style.TextDirection? textDirection, optional long lineHeight, optional androidx.compose.ui.text.style.TextIndent? textIndent, optional androidx.compose.ui.text.PlatformParagraphStyle? platformStyle, optional androidx.compose.ui.text.style.LineHeightStyle? lineHeightStyle);
+    ctor @androidx.compose.ui.text.ExperimentalTextApi public ParagraphStyle(optional androidx.compose.ui.text.style.TextAlign? textAlign, optional androidx.compose.ui.text.style.TextDirection? textDirection, optional long lineHeight, optional androidx.compose.ui.text.style.TextIndent? textIndent, optional @androidx.compose.ui.text.ExperimentalTextApi androidx.compose.ui.text.PlatformParagraphStyle? platformStyle, optional @androidx.compose.ui.text.ExperimentalTextApi androidx.compose.ui.text.style.LineHeightStyle? lineHeightStyle);
     ctor public ParagraphStyle(optional androidx.compose.ui.text.style.TextAlign? textAlign, optional androidx.compose.ui.text.style.TextDirection? textDirection, optional long lineHeight, optional androidx.compose.ui.text.style.TextIndent? textIndent);
     method public androidx.compose.ui.text.ParagraphStyle copy(optional androidx.compose.ui.text.style.TextAlign? textAlign, optional androidx.compose.ui.text.style.TextDirection? textDirection, optional long lineHeight, optional androidx.compose.ui.text.style.TextIndent? textIndent);
     method @androidx.compose.ui.text.ExperimentalTextApi public androidx.compose.ui.text.ParagraphStyle copy(optional androidx.compose.ui.text.style.TextAlign? textAlign, optional androidx.compose.ui.text.style.TextDirection? textDirection, optional long lineHeight, optional androidx.compose.ui.text.style.TextIndent? textIndent, optional androidx.compose.ui.text.PlatformParagraphStyle? platformStyle, optional androidx.compose.ui.text.style.LineHeightStyle? lineHeightStyle);
diff --git a/compose/ui/ui-text/samples/src/main/java/androidx/compose/ui/text/samples/AnnotatedStringBuilderSamples.kt b/compose/ui/ui-text/samples/src/main/java/androidx/compose/ui/text/samples/AnnotatedStringBuilderSamples.kt
index 5eb4cee..3c7f068 100644
--- a/compose/ui/ui-text/samples/src/main/java/androidx/compose/ui/text/samples/AnnotatedStringBuilderSamples.kt
+++ b/compose/ui/ui-text/samples/src/main/java/androidx/compose/ui/text/samples/AnnotatedStringBuilderSamples.kt
@@ -46,7 +46,8 @@
 
 @Sampled
 fun AnnotatedStringBuilderSample() {
-    with(AnnotatedString.Builder("Hello")) {
+    buildAnnotatedString {
+        append("Hello")
         // push green text style so that any appended text will be green
         pushStyle(SpanStyle(color = Color.Green))
         // append new text, this text will be rendered as green
@@ -64,7 +65,7 @@
 
 @Sampled
 fun AnnotatedStringBuilderPushSample() {
-    with(AnnotatedString.Builder()) {
+    buildAnnotatedString {
         // push green text color so that any appended text will be rendered green
         pushStyle(SpanStyle(color = Color.Green))
         // append string, this text will be rendered green
@@ -96,7 +97,7 @@
 
 @Sampled
 fun AnnotatedStringBuilderPushStringAnnotationSample() {
-    with(AnnotatedString.Builder()) {
+    buildAnnotatedString {
         // push a string annotation to be applied to any appended text after this point.
         pushStringAnnotation("ParagrapLabel", "paragraph1")
         // append a paragraph, the annotation "paragraph1" is attached
@@ -112,7 +113,7 @@
 
 @Sampled
 fun AnnotatedStringBuilderWithStyleSample() {
-    with(AnnotatedString.Builder()) {
+    buildAnnotatedString {
         withStyle(SpanStyle(color = Color.Green)) {
             // green text style will be applied to all text in this block
             append("Hello")
@@ -139,7 +140,7 @@
 
 @Sampled
 fun AnnotatedStringAddStringAnnotationSample() {
-    with(AnnotatedString.Builder()) {
+    buildAnnotatedString {
         append("link: Jetpack Compose")
         // attach a string annotation that stores a URL to the text "Jetpack Compose".
         addStringAnnotation(
@@ -149,4 +150,4 @@
             end = 21
         )
     }
-}
\ No newline at end of file
+}
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.android.kt
index effa15b..29121284 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.android.kt
@@ -69,7 +69,7 @@
 // AndroidParagraphIntrinsics. Should we consider just having one TextLayout class which
 // implements Paragraph and ParagraphIntrinsics? it seems like all of these types are immutable
 // and have similar sets of responsibilities.
-@OptIn(InternalPlatformTextApi::class)
+@OptIn(InternalPlatformTextApi::class, ExperimentalTextApi::class)
 internal class AndroidParagraph(
     val paragraphIntrinsics: AndroidParagraphIntrinsics,
     val maxLines: Int,
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt
index 8159fdc..4238314 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/extensions/SpannableExtensions.android.kt
@@ -202,6 +202,7 @@
     }
 }
 
+@OptIn(ExperimentalTextApi::class)
 private fun Spannable.setSpanStyle(
     spanStyleRange: AnnotatedString.Range<SpanStyle>,
     density: Density,
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ParagraphStyle.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ParagraphStyle.kt
index c9a37c1..e3ca5cd 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ParagraphStyle.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ParagraphStyle.kt
@@ -61,8 +61,10 @@
     val textDirection: TextDirection? = null,
     val lineHeight: TextUnit = TextUnit.Unspecified,
     val textIndent: TextIndent? = null,
+    @ExperimentalTextApi
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
     @get:ExperimentalTextApi val platformStyle: PlatformParagraphStyle? = null,
+    @ExperimentalTextApi
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
     @get:ExperimentalTextApi val lineHeightStyle: LineHeightStyle? = null
 ) {
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 24df62c..a886de7 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
@@ -96,6 +96,7 @@
     val background: Color = Color.Unspecified,
     val textDecoration: TextDecoration? = null,
     val shadow: Shadow? = null,
+    @ExperimentalTextApi
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
     @get:ExperimentalTextApi val platformStyle: PlatformSpanStyle? = null
 ) {
@@ -315,6 +316,7 @@
     /**
      * Brush to draw text. If not null, overrides [color].
      */
+    @ExperimentalTextApi
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
     @get:ExperimentalTextApi
     val brush: Brush? get() = this.textDrawStyle.brush
@@ -323,6 +325,7 @@
      * Opacity of text. This value is either provided along side Brush, or via alpha channel in
      * color.
      */
+    @ExperimentalTextApi
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
     @get:ExperimentalTextApi
     val alpha: Float get() = this.textDrawStyle.alpha
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 3d789db..123266e 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
@@ -54,6 +54,7 @@
 internal constructor(
     internal val spanStyle: SpanStyle,
     internal val paragraphStyle: ParagraphStyle,
+    @ExperimentalTextApi
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
     @get:ExperimentalTextApi val platformStyle: PlatformTextStyle? = null,
 ) {
@@ -564,6 +565,7 @@
     /**
      * The brush to use when drawing text. If not null, overrides [color].
      */
+    @ExperimentalTextApi
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
     @get:ExperimentalTextApi
     val brush: Brush? get() = this.spanStyle.brush
@@ -577,6 +579,7 @@
      * Opacity of text. This value is either provided along side Brush, or via alpha channel in
      * color.
      */
+    @ExperimentalTextApi
     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
     @get:ExperimentalTextApi
     val alpha: Float get() = this.spanStyle.alpha
diff --git a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/SpanStyleTest.kt b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/SpanStyleTest.kt
index e08b39c..0286047 100644
--- a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/SpanStyleTest.kt
+++ b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/SpanStyleTest.kt
@@ -39,6 +39,7 @@
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 
+@OptIn(ExperimentalTextApi::class)
 @RunWith(JUnit4::class)
 class SpanStyleTest {
     @Test
diff --git a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextStyleTest.kt b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextStyleTest.kt
index b5bdfd5..bd0599d 100644
--- a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextStyleTest.kt
+++ b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextStyleTest.kt
@@ -159,6 +159,7 @@
         assertThat(style.color).isEqualTo(color)
     }
 
+    @OptIn(ExperimentalTextApi::class)
     @Test
     fun `constructor with half-transparent color`() {
         val color = Color.Red.copy(alpha = 0.5f)
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index b3c46bb..a5944e3 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -3024,9 +3024,11 @@
     method public boolean getDismissOnBackPress();
     method public boolean getDismissOnClickOutside();
     method public androidx.compose.ui.window.SecureFlagPolicy getSecurePolicy();
+    method public boolean getUsePlatformDefaultWidth();
     property public final boolean dismissOnBackPress;
     property public final boolean dismissOnClickOutside;
     property public final androidx.compose.ui.window.SecureFlagPolicy securePolicy;
+    property public final boolean usePlatformDefaultWidth;
   }
 
   public interface DialogWindowProvider {
@@ -3046,12 +3048,14 @@
     method public boolean getExcludeFromSystemGesture();
     method public boolean getFocusable();
     method public androidx.compose.ui.window.SecureFlagPolicy getSecurePolicy();
+    method public boolean getUsePlatformDefaultWidth();
     property public final boolean clippingEnabled;
     property public final boolean dismissOnBackPress;
     property public final boolean dismissOnClickOutside;
     property public final boolean excludeFromSystemGesture;
     property public final boolean focusable;
     property public final androidx.compose.ui.window.SecureFlagPolicy securePolicy;
+    property public final boolean usePlatformDefaultWidth;
   }
 
   public enum SecureFlagPolicy {
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index af5d691..0458028 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -3243,11 +3243,11 @@
     method public boolean getDismissOnBackPress();
     method public boolean getDismissOnClickOutside();
     method public androidx.compose.ui.window.SecureFlagPolicy getSecurePolicy();
-    method @androidx.compose.ui.ExperimentalComposeUiApi public boolean getUsePlatformDefaultWidth();
+    method public boolean getUsePlatformDefaultWidth();
     property public final boolean dismissOnBackPress;
     property public final boolean dismissOnClickOutside;
     property public final androidx.compose.ui.window.SecureFlagPolicy securePolicy;
-    property @androidx.compose.ui.ExperimentalComposeUiApi public final boolean usePlatformDefaultWidth;
+    property public final boolean usePlatformDefaultWidth;
   }
 
   public interface DialogWindowProvider {
@@ -3268,14 +3268,14 @@
     method public boolean getExcludeFromSystemGesture();
     method public boolean getFocusable();
     method public androidx.compose.ui.window.SecureFlagPolicy getSecurePolicy();
-    method @androidx.compose.ui.ExperimentalComposeUiApi public boolean getUsePlatformDefaultWidth();
+    method public boolean getUsePlatformDefaultWidth();
     property public final boolean clippingEnabled;
     property public final boolean dismissOnBackPress;
     property public final boolean dismissOnClickOutside;
     property public final boolean excludeFromSystemGesture;
     property public final boolean focusable;
     property public final androidx.compose.ui.window.SecureFlagPolicy securePolicy;
-    property @androidx.compose.ui.ExperimentalComposeUiApi public final boolean usePlatformDefaultWidth;
+    property public final boolean usePlatformDefaultWidth;
   }
 
   public enum SecureFlagPolicy {
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index 1937f91..ced5b76 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -3060,9 +3060,11 @@
     method public boolean getDismissOnBackPress();
     method public boolean getDismissOnClickOutside();
     method public androidx.compose.ui.window.SecureFlagPolicy getSecurePolicy();
+    method public boolean getUsePlatformDefaultWidth();
     property public final boolean dismissOnBackPress;
     property public final boolean dismissOnClickOutside;
     property public final androidx.compose.ui.window.SecureFlagPolicy securePolicy;
+    property public final boolean usePlatformDefaultWidth;
   }
 
   public interface DialogWindowProvider {
@@ -3082,12 +3084,14 @@
     method public boolean getExcludeFromSystemGesture();
     method public boolean getFocusable();
     method public androidx.compose.ui.window.SecureFlagPolicy getSecurePolicy();
+    method public boolean getUsePlatformDefaultWidth();
     property public final boolean clippingEnabled;
     property public final boolean dismissOnBackPress;
     property public final boolean dismissOnClickOutside;
     property public final boolean excludeFromSystemGesture;
     property public final boolean focusable;
     property public final androidx.compose.ui.window.SecureFlagPolicy securePolicy;
+    property public final boolean usePlatformDefaultWidth;
   }
 
   public enum SecureFlagPolicy {
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidDialog.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidDialog.android.kt
index 65fe30b..48b889e 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidDialog.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidDialog.android.kt
@@ -79,8 +79,6 @@
     val dismissOnBackPress: Boolean = true,
     val dismissOnClickOutside: Boolean = true,
     val securePolicy: SecureFlagPolicy = SecureFlagPolicy.Inherit,
-    @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-    @get:ExperimentalComposeUiApi
     val usePlatformDefaultWidth: Boolean = true
 ) {
     @OptIn(ExperimentalComposeUiApi::class)
@@ -95,7 +93,6 @@
         usePlatformDefaultWidth = true
     )
 
-    @OptIn(ExperimentalComposeUiApi::class)
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (other !is DialogProperties) return false
@@ -108,7 +105,6 @@
         return true
     }
 
-    @OptIn(ExperimentalComposeUiApi::class)
     override fun hashCode(): Int {
         var result = dismissOnBackPress.hashCode()
         result = 31 * result + dismissOnClickOutside.hashCode()
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.android.kt
index c036b23..1250af4 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.android.kt
@@ -113,8 +113,6 @@
     val securePolicy: SecureFlagPolicy = SecureFlagPolicy.Inherit,
     val excludeFromSystemGesture: Boolean = true,
     val clippingEnabled: Boolean = true,
-    @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
-    @get:ExperimentalComposeUiApi
     val usePlatformDefaultWidth: Boolean = false
 ) {
     @OptIn(ExperimentalComposeUiApi::class)
@@ -135,7 +133,6 @@
         usePlatformDefaultWidth = false
     )
 
-    @OptIn(ExperimentalComposeUiApi::class)
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (other !is PopupProperties) return false
@@ -151,7 +148,6 @@
         return true
     }
 
-    @OptIn(ExperimentalComposeUiApi::class)
     override fun hashCode(): Int {
         var result = dismissOnBackPress.hashCode()
         result = 31 * result + focusable.hashCode()
diff --git a/datastore/datastore-core-okio/build.gradle b/datastore/datastore-core-okio/build.gradle
index c73667d..313f4de 100644
--- a/datastore/datastore-core-okio/build.gradle
+++ b/datastore/datastore-core-okio/build.gradle
@@ -103,7 +103,7 @@
         android = Publish.NONE
         jvm = Publish.SNAPSHOT_AND_RELEASE
         linux = Publish.SNAPSHOT_AND_RELEASE
-
+        mac = Publish.SNAPSHOT_AND_RELEASE
     }
     mavenGroup = LibraryGroups.DATASTORE
     inceptionYear = "2020"
diff --git a/datastore/datastore-core/build.gradle b/datastore/datastore-core/build.gradle
index 8a95cde..9ddc77b 100644
--- a/datastore/datastore-core/build.gradle
+++ b/datastore/datastore-core/build.gradle
@@ -112,6 +112,7 @@
         android = Publish.NONE
         jvm = Publish.SNAPSHOT_AND_RELEASE
         linux = Publish.SNAPSHOT_AND_RELEASE
+        mac = Publish.SNAPSHOT_AND_RELEASE
     }
     mavenGroup = LibraryGroups.DATASTORE
     inceptionYear = "2020"
diff --git a/development/build_log_processor.sh b/development/build_log_processor.sh
index 90cda20..a9b931a 100755
--- a/development/build_log_processor.sh
+++ b/development/build_log_processor.sh
@@ -33,10 +33,6 @@
   usage
 fi
 
-summarizeOnFailure=false
-if [[ " ${@} " =~ " -Pandroidx.summarizeStderr " ]]; then
-  summarizeOnFailure=true
-fi
 validateNoUnrecognizedMessagesOnSuccess=false
 validateArgument="-Pandroidx.validateNoUnrecognizedMessages"
 if [[ " ${@} " =~ " $validateArgument " ]]; then
@@ -94,19 +90,17 @@
     fi
   fi
 else
-  if [ "$summarizeOnFailure" == "true" ]; then
-    echo >&2
-    echo "############################################################################" >&2
-    echo "Attempting to locate the relevant error messages via build_log_simplifier.py" >&2
-    echo "############################################################################" >&2
-    echo >&2
-    # Try to identify the most relevant lines of output, and put them at the bottom of the
-    # output where they will also be placed into the build failure email.
-    # TODO: We may be able to stop cleaning up Gradle's output after Gradle can do this on its own:
-    # https://github.com/gradle/gradle/issues/1005
-    # and https://github.com/gradle/gradle/issues/13090
-    summaryLog="$LOG_DIR/error_summary.log"
-    $SCRIPT_PATH/build_log_simplifier.py $logFile | tee "$summaryLog" >&2
-  fi
+  echo >&2
+  echo "############################################################################" >&2
+  echo "Attempting to locate the relevant error messages via build_log_simplifier.py" >&2
+  echo "############################################################################" >&2
+  echo >&2
+  # Try to identify the most relevant lines of output, and put them at the bottom of the
+  # output where they will also be placed into the build failure email.
+  # TODO: We may be able to stop cleaning up Gradle's output after Gradle can do this on its own:
+  # https://github.com/gradle/gradle/issues/1005
+  # and https://github.com/gradle/gradle/issues/13090
+  summaryLog="$LOG_DIR/error_summary.log"
+  $SCRIPT_PATH/build_log_simplifier.py $logFile | tee "$summaryLog" >&2
   exit 1
 fi
diff --git a/development/build_log_simplifier/message-flakes.ignore b/development/build_log_simplifier/message-flakes.ignore
index a0f4984..4999faa 100644
--- a/development/build_log_simplifier/message-flakes.ignore
+++ b/development/build_log_simplifier/message-flakes.ignore
@@ -130,3 +130,7 @@
 # b/225244932
 Index data read correctly
 Could not read index from network cache: null
+# androidx-studio-integration uses custom AGP and lint
+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\.
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index 44d8441..7a8eb1d 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -4,10 +4,10 @@
 }
 
 dependencies {
-    docs("androidx.activity:activity:1.5.0-rc01")
-    docs("androidx.activity:activity-compose:1.5.0-rc01")
-    samples("androidx.activity:activity-compose-samples:1.5.0-rc01")
-    docs("androidx.activity:activity-ktx:1.5.0-rc01")
+    docs("androidx.activity:activity:1.5.0")
+    docs("androidx.activity:activity-compose:1.5.0")
+    samples("androidx.activity:activity-compose-samples:1.5.0")
+    docs("androidx.activity:activity-ktx:1.5.0")
     docs("androidx.ads:ads-identifier:1.0.0-alpha04")
     docs("androidx.ads:ads-identifier-provider:1.0.0-alpha04")
     docs("androidx.annotation:annotation:1.4.0")
@@ -47,54 +47,54 @@
     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-rc01")
-    docs("androidx.compose.animation:animation-core:1.2.0-rc01")
-    docs("androidx.compose.animation:animation-graphics:1.2.0-rc01")
-    samples("androidx.compose.animation:animation-samples:1.2.0-rc01")
-    samples("androidx.compose.animation:animation-core-samples:1.2.0-rc01")
-    samples("androidx.compose.animation:animation-graphics-samples:1.2.0-rc01")
-    docs("androidx.compose.foundation:foundation:1.2.0-rc01")
-    docs("androidx.compose.foundation:foundation-layout:1.2.0-rc01")
-    samples("androidx.compose.foundation:foundation-layout-samples:1.2.0-rc01")
-    samples("androidx.compose.foundation:foundation-samples:1.2.0-rc01")
+    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.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-rc01")
-    docs("androidx.compose.material:material-icons-core:1.2.0-rc01")
-    samples("androidx.compose.material:material-icons-core-samples:1.2.0-rc01")
-    docs("androidx.compose.material:material-ripple:1.2.0-rc01")
-    samples("androidx.compose.material:material-samples:1.2.0-rc01")
-    docs("androidx.compose.runtime:runtime:1.2.0-rc01")
-    docs("androidx.compose.runtime:runtime-livedata:1.2.0-rc01")
-    samples("androidx.compose.runtime:runtime-livedata-samples:1.2.0-rc01")
-    docs("androidx.compose.runtime:runtime-rxjava2:1.2.0-rc01")
-    samples("androidx.compose.runtime:runtime-rxjava2-samples:1.2.0-rc01")
-    docs("androidx.compose.runtime:runtime-rxjava3:1.2.0-rc01")
-    samples("androidx.compose.runtime:runtime-rxjava3-samples:1.2.0-rc01")
-    docs("androidx.compose.runtime:runtime-saveable:1.2.0-rc01")
-    samples("androidx.compose.runtime:runtime-saveable-samples:1.2.0-rc01")
-    samples("androidx.compose.runtime:runtime-samples:1.2.0-rc01")
-    docs("androidx.compose.ui:ui:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-geometry:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-graphics:1.2.0-rc01")
-    samples("androidx.compose.ui:ui-graphics-samples:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-test:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-test-junit4:1.2.0-rc01")
-    samples("androidx.compose.ui:ui-test-samples:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-text:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-text-google-fonts:1.2.0-rc01")
-    samples("androidx.compose.ui:ui-text-samples:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-tooling:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-tooling-data:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-tooling-preview:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-unit:1.2.0-rc01")
-    samples("androidx.compose.ui:ui-unit-samples:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-util:1.2.0-rc01")
-    docs("androidx.compose.ui:ui-viewbinding:1.2.0-rc01")
-    samples("androidx.compose.ui:ui-viewbinding-samples:1.2.0-rc01")
-    samples("androidx.compose.ui:ui-samples:1.2.0-rc01")
+    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.concurrent:concurrent-futures:1.1.0")
     docs("androidx.concurrent:concurrent-futures-ktx:1.1.0")
     docs("androidx.contentpager:contentpager:1.0.0")
@@ -136,9 +136,9 @@
     docs("androidx.enterprise:enterprise-feedback:1.1.0")
     docs("androidx.enterprise:enterprise-feedback-testing:1.1.0")
     docs("androidx.exifinterface:exifinterface:1.3.3")
-    docs("androidx.fragment:fragment:1.5.0-rc01")
-    docs("androidx.fragment:fragment-ktx:1.5.0-rc01")
-    docs("androidx.fragment:fragment-testing:1.5.0-rc01")
+    docs("androidx.fragment:fragment:1.5.0")
+    docs("androidx.fragment:fragment-ktx:1.5.0")
+    docs("androidx.fragment:fragment-testing:1.5.0")
     docs("androidx.glance:glance:1.0.0-alpha03")
     docs("androidx.glance:glance-appwidget:1.0.0-alpha03")
     docs("androidx.glance:glance-appwidget-proto:1.0.0-alpha03")
diff --git a/emoji2/emoji2-views-helper/AndroidManifest.xml b/emoji2/emoji2-views-helper/AndroidManifest.xml
index 1597e30..95c4426 100644
--- a/emoji2/emoji2-views-helper/AndroidManifest.xml
+++ b/emoji2/emoji2-views-helper/AndroidManifest.xml
@@ -13,4 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest package="androidx.emoji2.viewsintegration"/>
+<manifest />
diff --git a/fragment/fragment-ktx/build.gradle b/fragment/fragment-ktx/build.gradle
index c34c388..982978f 100644
--- a/fragment/fragment-ktx/build.gradle
+++ b/fragment/fragment-ktx/build.gradle
@@ -25,7 +25,7 @@
 
 dependencies {
     api(project(":fragment:fragment"))
-    api("androidx.activity:activity-ktx:1.5.0-rc01") {
+    api("androidx.activity:activity-ktx:1.5.0") {
         because "Mirror fragment dependency graph for -ktx artifacts"
     }
     api("androidx.core:core-ktx:1.2.0") {
diff --git a/fragment/fragment/build.gradle b/fragment/fragment/build.gradle
index 0d78a13..309118a 100644
--- a/fragment/fragment/build.gradle
+++ b/fragment/fragment/build.gradle
@@ -29,7 +29,7 @@
     api("androidx.collection:collection:1.1.0")
     api("androidx.viewpager:viewpager:1.0.0")
     api("androidx.loader:loader:1.0.0")
-    api("androidx.activity:activity:1.5.0-rc01")
+    api("androidx.activity:activity:1.5.0")
     api("androidx.lifecycle:lifecycle-livedata-core:2.5.0")
     api("androidx.lifecycle:lifecycle-viewmodel:2.5.0")
     api("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.5.0")
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 3d0c629..2cfa627 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -1982,12 +1982,16 @@
      */
     @SuppressWarnings("deprecation")
     void restoreChildFragmentState(@Nullable Bundle savedInstanceState) {
-        if (savedInstanceState != null) {
-            Parcelable p = savedInstanceState.getParcelable(
-                    FragmentManager.SAVED_STATE_TAG);
-            if (p != null) {
-                mChildFragmentManager.restoreSaveStateInternal(p);
-                mChildFragmentManager.dispatchCreate();
+        if (savedInstanceState != null && mSavedFragmentState != null) {
+            FragmentState fs =
+                    mSavedFragmentState.getParcelable(FragmentManager.FRAGMENT_STATE_TAG);
+            if (fs != null) {
+                Parcelable p = fs.mSavedFragmentState.getParcelable(
+                        FragmentManager.SAVED_STATE_TAG);
+                if (p != null) {
+                    mChildFragmentManager.restoreSaveStateInternal(p);
+                    mChildFragmentManager.dispatchCreate();
+                }
             }
         }
     }
@@ -3122,10 +3126,17 @@
         }
     }
 
+    @SuppressWarnings("deprecation")
     void performViewCreated() {
         // since calling super.onViewCreated() is not required, we do not need to set and check the
         // `mCalled` flag
-        onViewCreated(mView, mSavedFragmentState);
+        Bundle basicState = null;
+        if (mSavedFragmentState != null) {
+            FragmentState fs = mSavedFragmentState.getParcelable(
+                    FragmentManager.FRAGMENT_STATE_TAG);
+            basicState = fs != null ? fs.mSavedFragmentState : null;
+        }
+        onViewCreated(mView, basicState);
         mChildFragmentManager.dispatchViewCreated();
     }
 
@@ -3143,12 +3154,19 @@
         mChildFragmentManager.dispatchActivityCreated();
     }
 
+    @SuppressWarnings("deprecation")
     private void restoreViewState() {
         if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
             Log.d(FragmentManager.TAG, "moveto RESTORE_VIEW_STATE: " + this);
         }
         if (mView != null) {
-            restoreViewState(mSavedFragmentState);
+            Bundle basicBundle = null;
+            if (mSavedFragmentState != null) {
+                FragmentState fs =
+                        mSavedFragmentState.getParcelable(FragmentManager.FRAGMENT_STATE_TAG);
+                basicBundle = fs != null ? fs.mSavedFragmentState : null;
+            }
+            restoreViewState(basicBundle);
         }
         mSavedFragmentState = null;
     }
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 b1eae01..fe07b8d 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -2498,6 +2498,7 @@
                             getFragmentFactory(), stateBundle);
                 }
                 Fragment f = fragmentStateManager.getFragment();
+                f.mSavedFragmentState = stateBundle;
                 f.mFragmentManager = this;
                 if (isLoggingEnabled(Log.VERBOSE)) {
                     Log.v(TAG, "restoreSaveState: active (" + f.mWho + "): " + f);
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentState.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentState.java
index d187e4f..34ecc45 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentState.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentState.java
@@ -73,6 +73,7 @@
      * Instantiates the Fragment from this state.
      */
     @NonNull
+    @SuppressWarnings("deprecation")
     Fragment instantiate(@NonNull FragmentFactory fragmentFactory,
             @NonNull ClassLoader classLoader) {
         Fragment fragment = fragmentFactory.instantiate(classLoader, mClassName);
@@ -87,14 +88,18 @@
         fragment.mDetached = mDetached;
         fragment.mHidden = mHidden;
         fragment.mMaxState = Lifecycle.State.values()[mMaxLifecycleState];
-        if (mSavedFragmentState != null) {
-            fragment.mSavedFragmentState = mSavedFragmentState;
-        } else {
-            // 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
-            fragment.mSavedFragmentState = new Bundle();
+
+        // 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
+        if (mSavedFragmentState == null) {
+            mSavedFragmentState = new Bundle();
         }
+        // Construct a new Bundle of all of the information we have
+        // restored from this FragmentState object
+        Bundle savedFragmentState = new Bundle();
+        savedFragmentState.putParcelable(FragmentManager.FRAGMENT_STATE_TAG, this);
+        fragment.mSavedFragmentState = savedFragmentState;
         return fragment;
     }
 
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 ce95f94..25cc18d 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
@@ -87,6 +87,7 @@
         // Instantiate the fragment's library states in FragmentState
         FragmentState fs = state.getParcelable(FragmentManager.FRAGMENT_STATE_TAG);
         mFragment = fs.instantiate(fragmentFactory, classLoader);
+        mFragment.mSavedFragmentState = state;
 
         // Instantiate the fragment's arguments
         Bundle arguments = state.getBundle(FragmentManager.FRAGMENT_ARGUMENTS_TAG);
@@ -125,16 +126,7 @@
         mFragment.mTargetWho = mFragment.mTarget != null ? mFragment.mTarget.mWho : null;
         mFragment.mTarget = null;
 
-        FragmentState fs = state.getParcelable(FragmentManager.FRAGMENT_STATE_TAG);
-        if (fs.mSavedFragmentState != null) {
-            mFragment.mSavedFragmentState = fs.mSavedFragmentState;
-        } else {
-            // 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 = new Bundle();
-        }
-
+        mFragment.mSavedFragmentState = state;
         mFragment.mArguments = state.getBundle(FragmentManager.FRAGMENT_ARGUMENTS_TAG);
     }
 
@@ -397,20 +389,28 @@
         }
     }
 
+    @SuppressWarnings("deprecation")
     void ensureInflatedView() {
         if (mFragment.mFromLayout && mFragment.mInLayout && !mFragment.mPerformedCreateView) {
             if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
                 Log.d(TAG, "moveto CREATE_VIEW: " + mFragment);
             }
+            Bundle basicState = null;
+            if (mFragment.mSavedFragmentState != null) {
+                FragmentState fs =
+                        mFragment.mSavedFragmentState.getParcelable(
+                                FragmentManager.FRAGMENT_STATE_TAG);
+                basicState = fs != null ? fs.mSavedFragmentState : null;
+            }
             mFragment.performCreateView(mFragment.performGetLayoutInflater(
-                    mFragment.mSavedFragmentState), null, mFragment.mSavedFragmentState);
+                    basicState), null, basicState);
             if (mFragment.mView != null) {
                 mFragment.mView.setSaveFromParentEnabled(false);
                 mFragment.mView.setTag(R.id.fragment_container_view_tag, mFragment);
                 if (mFragment.mHidden) mFragment.mView.setVisibility(View.GONE);
                 mFragment.performViewCreated();
                 mDispatcher.dispatchOnFragmentViewCreated(
-                        mFragment, mFragment.mView, mFragment.mSavedFragmentState, false);
+                        mFragment, mFragment.mView, basicState, false);
                 mFragment.mState = Fragment.VIEW_CREATED;
             }
         }
@@ -422,22 +422,26 @@
             return;
         }
         mFragment.mSavedFragmentState.setClassLoader(classLoader);
-        mFragment.mSavedViewState = mFragment.mSavedFragmentState.getSparseParcelableArray(
-                VIEW_STATE_TAG);
-        mFragment.mSavedViewRegistryState = mFragment.mSavedFragmentState.getBundle(
-                VIEW_REGISTRY_STATE_TAG);
-        mFragment.mTargetWho = mFragment.mSavedFragmentState.getString(
-                TARGET_STATE_TAG);
-        if (mFragment.mTargetWho != null) {
-            mFragment.mTargetRequestCode = mFragment.mSavedFragmentState.getInt(
-                    TARGET_REQUEST_CODE_STATE_TAG, 0);
-        }
-        if (mFragment.mSavedUserVisibleHint != null) {
-            mFragment.mUserVisibleHint = mFragment.mSavedUserVisibleHint;
-            mFragment.mSavedUserVisibleHint = null;
-        } else {
-            mFragment.mUserVisibleHint = mFragment.mSavedFragmentState.getBoolean(
-                    USER_VISIBLE_HINT_TAG, true);
+        FragmentState fs =
+                mFragment.mSavedFragmentState.getParcelable(FragmentManager.FRAGMENT_STATE_TAG);
+        if (fs != null) {
+            mFragment.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
+                    VIEW_STATE_TAG);
+            mFragment.mSavedViewRegistryState = fs.mSavedFragmentState.getBundle(
+                    VIEW_REGISTRY_STATE_TAG);
+            mFragment.mTargetWho = fs.mSavedFragmentState.getString(
+                    TARGET_STATE_TAG);
+            if (mFragment.mTargetWho != null) {
+                mFragment.mTargetRequestCode = fs.mSavedFragmentState.getInt(
+                        TARGET_REQUEST_CODE_STATE_TAG, 0);
+            }
+            if (mFragment.mSavedUserVisibleHint != null) {
+                mFragment.mUserVisibleHint = mFragment.mSavedUserVisibleHint;
+                mFragment.mSavedUserVisibleHint = null;
+            } else {
+                mFragment.mUserVisibleHint = fs.mSavedFragmentState.getBoolean(
+                        USER_VISIBLE_HINT_TAG, true);
+            }
         }
         if (!mFragment.mUserVisibleHint) {
             mFragment.mDeferStart = true;
@@ -482,22 +486,29 @@
         mDispatcher.dispatchOnFragmentAttached(mFragment, false);
     }
 
+    @SuppressWarnings("deprecation")
     void create() {
         if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
             Log.d(TAG, "moveto CREATED: " + mFragment);
         }
+        Bundle basicState = null;
+        if (mFragment.mSavedFragmentState != null) {
+            FragmentState fs =
+                    mFragment.mSavedFragmentState.getParcelable(
+                            FragmentManager.FRAGMENT_STATE_TAG);
+            basicState = fs != null ? fs.mSavedFragmentState : null;
+        }
         if (!mFragment.mIsCreated) {
-            mDispatcher.dispatchOnFragmentPreCreated(
-                    mFragment, mFragment.mSavedFragmentState, false);
-            mFragment.performCreate(mFragment.mSavedFragmentState);
-            mDispatcher.dispatchOnFragmentCreated(
-                    mFragment, mFragment.mSavedFragmentState, false);
+            mDispatcher.dispatchOnFragmentPreCreated(mFragment, basicState, false);
+            mFragment.performCreate(basicState);
+            mDispatcher.dispatchOnFragmentCreated(mFragment, basicState, false);
         } else {
-            mFragment.restoreChildFragmentState(mFragment.mSavedFragmentState);
+            mFragment.restoreChildFragmentState(basicState);
             mFragment.mState = Fragment.CREATED;
         }
     }
 
+    @SuppressWarnings("deprecation")
     void createView() {
         if (mFragment.mFromLayout) {
             // This case is handled by ensureInflatedView(), so there's nothing
@@ -538,7 +549,13 @@
             }
         }
         mFragment.mContainer = container;
-        mFragment.performCreateView(layoutInflater, container, mFragment.mSavedFragmentState);
+        Bundle basicState = null;
+        if (mFragment.mSavedFragmentState != null) {
+            FragmentState fs =
+                    mFragment.mSavedFragmentState.getParcelable(FragmentManager.FRAGMENT_STATE_TAG);
+            basicState = fs != null ? fs.mSavedFragmentState : null;
+        }
+        mFragment.performCreateView(layoutInflater, container, basicState);
         if (mFragment.mView != null) {
             mFragment.mView.setSaveFromParentEnabled(false);
             mFragment.mView.setTag(R.id.fragment_container_view_tag, mFragment);
@@ -568,7 +585,7 @@
             }
             mFragment.performViewCreated();
             mDispatcher.dispatchOnFragmentViewCreated(
-                    mFragment, mFragment.mView, mFragment.mSavedFragmentState, false);
+                    mFragment, mFragment.mView, basicState, false);
             int postOnViewCreatedVisibility = mFragment.mView.getVisibility();
             float postOnViewCreatedAlpha = mFragment.mView.getAlpha();
             mFragment.setPostOnViewCreatedAlpha(postOnViewCreatedAlpha);
@@ -589,13 +606,20 @@
         mFragment.mState = Fragment.VIEW_CREATED;
     }
 
+    @SuppressWarnings("deprecation")
     void activityCreated() {
         if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
             Log.d(TAG, "moveto ACTIVITY_CREATED: " + mFragment);
         }
-        mFragment.performActivityCreated(mFragment.mSavedFragmentState);
+        Bundle basicState = null;
+        if (mFragment.mSavedFragmentState != null) {
+            FragmentState fs =
+                    mFragment.mSavedFragmentState.getParcelable(FragmentManager.FRAGMENT_STATE_TAG);
+            basicState = fs != null ? fs.mSavedFragmentState : null;
+        }
+        mFragment.performActivityCreated(basicState);
         mDispatcher.dispatchOnFragmentActivityCreated(
-                mFragment, mFragment.mSavedFragmentState, false);
+                mFragment, basicState, false);
     }
 
     void start() {
@@ -658,6 +682,7 @@
     }
 
     @NonNull
+    @SuppressWarnings("deprecation")
     Bundle saveState() {
         FragmentState fs = new FragmentState(mFragment);
 
@@ -677,9 +702,15 @@
                             mFragment.mTargetRequestCode);
                 }
             }
-
         } else {
-            fs.mSavedFragmentState = mFragment.mSavedFragmentState;
+            if (mFragment.mSavedFragmentState != null) {
+                FragmentState savedFragmentState =
+                        mFragment.mSavedFragmentState.getParcelable(
+                                FragmentManager.FRAGMENT_STATE_TAG);
+                if (savedFragmentState != null) {
+                    fs.mSavedFragmentState = savedFragmentState.mSavedFragmentState;
+                }
+            }
         }
 
         Bundle stateBundle = new Bundle();
@@ -691,8 +722,7 @@
     @Nullable
     Fragment.SavedState saveInstanceState() {
         if (mFragment.mState > Fragment.INITIALIZING) {
-            Bundle result = saveBasicState();
-            return result != null ? new Fragment.SavedState(result) : null;
+            return new Fragment.SavedState(saveState());
         }
         return null;
     }
diff --git a/glance/glance-appwidget/build.gradle b/glance/glance-appwidget/build.gradle
index 3b13d9c..2b9509f 100644
--- a/glance/glance-appwidget/build.gradle
+++ b/glance/glance-appwidget/build.gradle
@@ -122,5 +122,6 @@
 LayoutGeneratorTask.registerLayoutGenerator(
         project,
         android,
-        /* layoutDirectory= */ file("src/androidMain/layoutTemplates")
+        /* containerLayoutDirectory= */ file("src/androidMain/layoutTemplates"),
+        /* childLayoutDirectory= */ file("src/androidMain/res/layout")
 )
diff --git a/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/GenerateRegistry.kt b/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/GenerateRegistry.kt
index 7f8735e..ccbb397 100644
--- a/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/GenerateRegistry.kt
+++ b/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/GenerateRegistry.kt
@@ -45,6 +45,8 @@
 internal fun generateRegistry(
     packageName: String,
     layouts: Map<File, List<ContainerProperties>>,
+    boxChildLayouts: Map<File, List<BoxChildProperties>>,
+    rowColumnChildLayouts: Map<File, List<RowColumnChildProperties>>,
     outputSourceDir: File,
 ) {
     outputSourceDir.mkdirs()
@@ -133,6 +135,24 @@
     file.addFunction(generatedChildrenApi21)
     file.addType(generatedContainerApi31)
 
+    // TODO: only register the box children on T+, since the layouts are in layout-v32
+    val generatedBoxChildren = propertySpec(
+        "generatedBoxChildren",
+        BoxChildrenMap,
+        INTERNAL,
+    ) {
+        initializer(buildBoxChildInitializer(boxChildLayouts))
+    }
+    file.addProperty(generatedBoxChildren)
+    val generatedRowColumnChildren = propertySpec(
+        "generatedRowColumnChildren",
+        RowColumnChildrenMap,
+        INTERNAL,
+    ) {
+        initializer(buildRowColumnChildInitializer(rowColumnChildLayouts))
+    }
+    file.addProperty(generatedRowColumnChildren)
+
     val generatedComplexLayouts = propertySpec("generatedComplexLayouts", LayoutsMap, INTERNAL) {
         initializer(buildComplexInitializer())
     }
@@ -201,6 +221,44 @@
     }
 }
 
+private fun buildBoxChildInitializer(layouts: Map<File, List<BoxChildProperties>>): CodeBlock =
+    buildCodeBlock {
+        withIndent {
+            addStatement("mapOf(")
+            withIndent {
+                add(
+                    layouts.map {
+                        it.key to createBoxChildFileInitializer(it.key, it.value)
+                    }
+                        .sortedBy { it.first.nameWithoutExtension }
+                        .map { it.second }
+                        .joinToCode("")
+                )
+            }
+            addStatement(")")
+        }
+    }
+
+private fun buildRowColumnChildInitializer(
+    layouts: Map<File, List<RowColumnChildProperties>>
+): CodeBlock =
+    buildCodeBlock {
+        withIndent {
+            addStatement("mapOf(")
+            withIndent {
+                add(
+                    layouts.map {
+                        it.key to createRowColumnChildFileInitializer(it.key, it.value)
+                    }
+                        .sortedBy { it.first.nameWithoutExtension }
+                        .map { it.second }
+                        .joinToCode("")
+                )
+            }
+            addStatement(")")
+        }
+    }
+
 private fun buildComplexInitializer(): CodeBlock {
     return buildCodeBlock {
         addStatement("mapOf(")
@@ -262,6 +320,42 @@
         }
     }
 
+private fun createBoxChildFileInitializer(
+    layout: File,
+    generated: List<BoxChildProperties>
+): CodeBlock =
+    buildCodeBlock {
+        val viewType = layout.nameWithoutExtension.toLayoutType()
+        generated.forEach { props ->
+            addBoxChild(
+                resourceName = makeBoxChildResourceName(
+                    layout,
+                    props.horizontalAlignment,
+                    props.verticalAlignment
+                ),
+                viewType = viewType,
+                horizontalAlignment = props.horizontalAlignment,
+                verticalAlignment = props.verticalAlignment,
+            )
+        }
+    }
+
+private fun createRowColumnChildFileInitializer(
+    layout: File,
+    generated: List<RowColumnChildProperties>
+): CodeBlock =
+    buildCodeBlock {
+        val viewType = layout.nameWithoutExtension.toLayoutType()
+        generated.forEach { props ->
+            addRowColumnChild(
+                resourceName = makeRowColumnChildResourceName(layout, props.width, props.height),
+                viewType = viewType,
+                width = props.width,
+                height = props.height,
+            )
+        }
+    }
+
 private fun createChildrenInitializer(
     layout: File,
     generated: List<ContainerProperties>,
@@ -350,8 +444,41 @@
     addStatement(") to %T(layoutId = R.layout.$resourceName),", ContainerInfo)
 }
 
+private fun CodeBlock.Builder.addBoxChild(
+    resourceName: String,
+    viewType: String,
+    horizontalAlignment: HorizontalAlignment,
+    verticalAlignment: VerticalAlignment,
+) {
+    addStatement("%T(", BoxChildSelector)
+    withIndent {
+        addStatement("type = %M,", makeViewType(viewType))
+        addStatement("horizontalAlignment = %M, ", horizontalAlignment.code)
+        addStatement("verticalAlignment = %M, ", verticalAlignment.code)
+    }
+    addStatement(") to %T(layoutId = R.layout.$resourceName),", LayoutInfo)
+}
+
+private fun CodeBlock.Builder.addRowColumnChild(
+    resourceName: String,
+    viewType: String,
+    width: ValidSize,
+    height: ValidSize,
+) {
+    addStatement("%T(", RowColumnChildSelector)
+    withIndent {
+        addStatement("type = %M,", makeViewType(viewType))
+        addStatement("expandWidth = %L, ", width == ValidSize.Expand)
+        addStatement("expandHeight = %L, ", height == ValidSize.Expand)
+    }
+    addStatement(") to %T(layoutId = R.layout.$resourceName),", LayoutInfo)
+}
+
 private val ContainerSelector = ClassName("androidx.glance.appwidget", "ContainerSelector")
 private val SizeSelector = ClassName("androidx.glance.appwidget", "SizeSelector")
+private val BoxChildSelector = ClassName("androidx.glance.appwidget", "BoxChildSelector")
+private val RowColumnChildSelector =
+    ClassName("androidx.glance.appwidget", "RowColumnChildSelector")
 private val LayoutInfo = ClassName("androidx.glance.appwidget", "LayoutInfo")
 private val ContainerInfo = ClassName("androidx.glance.appwidget", "ContainerInfo")
 private val ContainerMap = Map::class.asTypeName().parameterizedBy(ContainerSelector, ContainerInfo)
@@ -381,6 +508,9 @@
 private val LayoutType = ClassName("androidx.glance.appwidget", "LayoutType")
 private val ChildrenMap = Map::class.asTypeName().parameterizedBy(INT, SizeSelectorToIntMap)
 private val ContainerChildrenMap = Map::class.asTypeName().parameterizedBy(LayoutType, ChildrenMap)
+private val BoxChildrenMap = Map::class.asTypeName().parameterizedBy(BoxChildSelector, LayoutInfo)
+private val RowColumnChildrenMap =
+    Map::class.asTypeName().parameterizedBy(RowColumnChildSelector, LayoutInfo)
 
 private fun makeViewType(name: String) =
     MemberName("androidx.glance.appwidget.LayoutType", name)
@@ -443,6 +573,28 @@
         pos
     ).joinToString(separator = "_")
 
+internal fun makeBoxChildResourceName(
+    file: File,
+    horizontalAlignment: HorizontalAlignment?,
+    verticalAlignment: VerticalAlignment?
+) =
+    listOf(
+        file.nameWithoutExtension,
+        horizontalAlignment?.resourceName,
+        verticalAlignment?.resourceName,
+    ).joinToString(separator = "_")
+
+internal fun makeRowColumnChildResourceName(
+    file: File,
+    width: ValidSize,
+    height: ValidSize,
+) =
+    listOf(
+        file.nameWithoutExtension,
+        if (width == ValidSize.Expand) "expandwidth" else "wrapwidth",
+        if (height == ValidSize.Expand) "expandheight" else "wrapheight",
+    ).joinToString(separator = "_")
+
 internal fun makeIdName(pos: Int, width: ValidSize, height: ValidSize) =
     listOf(
         "childStub$pos",
diff --git a/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/LayoutGenerator.kt b/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/LayoutGenerator.kt
index 74ce99f..480095c4 100644
--- a/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/LayoutGenerator.kt
+++ b/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/LayoutGenerator.kt
@@ -74,14 +74,17 @@
      * information extracted from the input.
      */
     fun generateAllFiles(
-        files: List<File>,
+        containerFiles: List<File>,
+        childrenFiles: List<File>,
         outputResourcesDir: File
     ): GeneratedFiles {
         val outputLayoutDir = outputResourcesDir.resolve("layout")
         val outputLayoutDirS = outputResourcesDir.resolve("layout-v31")
+        val outputLayoutDirT = outputResourcesDir.resolve("layout-v33")
         val outputValueDir = outputResourcesDir.resolve("values")
         outputLayoutDir.mkdirs()
         outputLayoutDirS.mkdirs()
+        outputLayoutDirT.mkdirs()
         outputValueDir.mkdirs()
         val generatedFiles = generateSizeLayouts(outputLayoutDir) +
             generateComplexLayouts(outputLayoutDir) +
@@ -90,10 +93,17 @@
             generateContainersChildrenBeforeS(outputLayoutDir) +
             generateRootElements(outputLayoutDir) +
             generateRootAliases(outputValueDir)
+        val topLevelLayouts = containerFiles + childrenFiles.filter { isTopLevelLayout(it) }
         return GeneratedFiles(
-            generatedContainers = files.associateWith {
+            generatedContainers = containerFiles.associateWith {
                 generateContainers(it, outputLayoutDir)
             },
+            generatedBoxChildren = topLevelLayouts.associateWith {
+                generateBoxChildrenForT(it, outputLayoutDirT)
+            },
+            generatedRowColumnChildren = topLevelLayouts.associateWith {
+                generateRowColumnChildrenForT(it, outputLayoutDirT)
+            },
             extraFiles = generatedFiles,
         )
     }
@@ -413,6 +423,42 @@
         }
     }
 
+    private fun generateBoxChildrenForT(
+        file: File,
+        outputLayoutDir: File,
+    ): List<BoxChildProperties> =
+        crossProduct(
+            HorizontalAlignment.values().toList(),
+            VerticalAlignment.values().toList()
+        ).map { (horizontalAlignment, verticalAlignment) ->
+            val generated = generateAlignedLayout(
+                parseLayoutTemplate(file),
+                horizontalAlignment,
+                verticalAlignment,
+            )
+            val output = outputLayoutDir.resolveRes(
+                makeBoxChildResourceName(file, horizontalAlignment, verticalAlignment)
+            )
+            writeGeneratedLayout(generated, output)
+            BoxChildProperties(output, horizontalAlignment, verticalAlignment)
+        }
+
+    private fun generateRowColumnChildrenForT(
+        file: File,
+        outputLayoutDir: File,
+    ): List<RowColumnChildProperties> =
+        listOf(
+            Pair(ValidSize.Expand, ValidSize.Wrap),
+            Pair(ValidSize.Wrap, ValidSize.Expand),
+        ).map { (width, height) ->
+            val generated = generateSimpleLayout(parseLayoutTemplate(file), width, height)
+            val output = outputLayoutDir.resolveRes(
+                makeRowColumnChildResourceName(file, width, height)
+            )
+            writeGeneratedLayout(generated, output)
+            RowColumnChildProperties(output, width, height)
+        }
+
     /**
      * Generate a simple layout.
      *
@@ -442,6 +488,25 @@
         return generated
     }
 
+    /**
+     * This function is used to generate FrameLayout children with "layout_gravity" set for
+     * Android T+. We can ignore size here since it is set programmatically for T+.
+     */
+    private fun generateAlignedLayout(
+        document: Document,
+        horizontalAlignment: HorizontalAlignment,
+        verticalAlignment: VerticalAlignment,
+    ) = generateSimpleLayout(document, ValidSize.Wrap, ValidSize.Wrap).apply {
+        documentElement.attributes.setNamedItemNS(
+            androidGravity(
+                listOfNotNull(
+                    horizontalAlignment.resourceName,
+                    verticalAlignment.resourceName
+                ).joinToString(separator = "|")
+            )
+        )
+    }
+
     private fun generateRootAliases(outputValueDir: File) =
         generateRes(outputValueDir, "layouts") {
             val root = createElement("resources")
@@ -474,6 +539,11 @@
         writeGeneratedLayout(document, file)
         return file
     }
+
+    private fun isTopLevelLayout(file: File) =
+        parseLayoutTemplate(file).run {
+            documentElement.appAttr("glance_isTopLevelLayout")?.nodeValue == "true"
+        }
 }
 
 /** Maximum number of children generated in containers. */
@@ -487,6 +557,8 @@
 
 internal data class GeneratedFiles(
     val generatedContainers: Map<File, List<ContainerProperties>>,
+    val generatedBoxChildren: Map<File, List<BoxChildProperties>>,
+    val generatedRowColumnChildren: Map<File, List<RowColumnChildProperties>>,
     val extraFiles: Set<File>
 )
 
@@ -504,6 +576,18 @@
     val verticalAlignment: VerticalAlignment?,
 )
 
+internal data class BoxChildProperties(
+    val generatedFile: File,
+    val horizontalAlignment: HorizontalAlignment,
+    val verticalAlignment: VerticalAlignment,
+)
+
+internal data class RowColumnChildProperties(
+    val generatedFile: File,
+    val width: ValidSize,
+    val height: ValidSize,
+)
+
 internal enum class ValidSize(val androidValue: String, val resourceName: String) {
     Wrap("wrap_content", "wrap"),
     Fixed("wrap_content", "fixed"),
@@ -557,6 +641,7 @@
 internal fun getChildMergeFilenameWithoutExtension(childCount: Int) = "merge_${childCount}child"
 
 private val AndroidNS = "http://schemas.android.com/apk/res/android"
+private val AppNS = "http://schemas.android.com/apk/res-auto"
 
 internal fun Document.androidAttr(name: String, value: String) =
     createAttributeNS(AndroidNS, "android:$name").apply {
@@ -566,6 +651,9 @@
 internal fun Node.androidAttr(name: String): Node? =
     attributes.getNamedItemNS(AndroidNS, name)
 
+internal fun Node.appAttr(name: String): Node? =
+    attributes.getNamedItemNS(AppNS, name)
+
 internal fun Document.attribute(name: String, value: String): Node? =
     createAttribute(name).apply { textContent = value }
 
diff --git a/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/gradle/LayoutGeneratorTask.kt b/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/gradle/LayoutGeneratorTask.kt
index 85212e9..fbe5c31 100644
--- a/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/gradle/LayoutGeneratorTask.kt
+++ b/glance/glance-appwidget/glance-layout-generator/src/main/kotlin/androidx/glance/appwidget/layoutgenerator/gradle/LayoutGeneratorTask.kt
@@ -16,7 +16,7 @@
 
 package androidx.glance.appwidget.layoutgenerator.gradle
 
-import androidx.glance.appwidget.layoutgenerator.ContainerProperties
+import androidx.glance.appwidget.layoutgenerator.GeneratedFiles
 import androidx.glance.appwidget.layoutgenerator.LayoutGenerator
 import androidx.glance.appwidget.layoutgenerator.cleanResources
 import androidx.glance.appwidget.layoutgenerator.generateRegistry
@@ -43,7 +43,11 @@
 
     @get:PathSensitive(PathSensitivity.NAME_ONLY)
     @get:InputDirectory
-    abstract val layoutDirectory: DirectoryProperty
+    abstract val containerLayoutDirectory: DirectoryProperty
+
+    @get:PathSensitive(PathSensitivity.NAME_ONLY)
+    @get:InputDirectory
+    abstract val childLayoutDirectory: DirectoryProperty
 
     @get:OutputDirectory
     abstract val outputSourceDir: DirectoryProperty
@@ -53,27 +57,35 @@
 
     @TaskAction
     fun execute() {
-        val generatedFiles = LayoutGenerator().generateAllFiles(
-            checkNotNull(layoutDirectory.get().asFile.listFiles()).asList(),
+        val generatedLayouts = LayoutGenerator().generateAllFiles(
+            checkNotNull(containerLayoutDirectory.get().asFile.listFiles()).asList(),
+            checkNotNull(childLayoutDirectory.get().asFile.listFiles()).asList(),
             outputResourcesDir.get().asFile
         )
         generateRegistry(
             packageName = outputModule,
-            layouts = generatedFiles.generatedContainers,
+            layouts = generatedLayouts.generatedContainers,
+            boxChildLayouts = generatedLayouts.generatedBoxChildren,
+            rowColumnChildLayouts = generatedLayouts.generatedRowColumnChildren,
             outputSourceDir = outputSourceDir.get().asFile
         )
-        val generatedContainers = generatedFiles.generatedContainers.extractGeneratedFiles()
         cleanResources(
             outputResourcesDir.get().asFile,
-            generatedContainers +
-                generatedFiles.extraFiles
+            generatedLayouts.extractGeneratedFiles()
         )
     }
 
-    private fun Map<File, List<ContainerProperties>>.extractGeneratedFiles(): Set<File> =
-        values.flatMap { containers ->
-            containers.map { it.generatedFile }
-        }.toSet()
+    private fun GeneratedFiles.extractGeneratedFiles(): Set<File> =
+        generatedContainers.values.flatMap { container ->
+            container.map { it.generatedFile }
+        }.toSet() +
+        generatedBoxChildren.values.flatMap { child ->
+            child.map { it.generatedFile }
+        }.toSet() +
+        generatedRowColumnChildren.values.flatMap { child ->
+            child.map { it.generatedFile }
+        }.toSet() +
+        extraFiles
 
     companion object {
         /**
@@ -83,7 +95,8 @@
         fun registerLayoutGenerator(
             project: Project,
             libraryExtension: LibraryExtension,
-            layoutDirectory: File
+            containerLayoutDirectory: File,
+            childLayoutDirectory: File,
         ) {
             libraryExtension.libraryVariants.all { variant ->
                 val variantName = variant.name
@@ -95,7 +108,8 @@
                 outputResourcesDir.mkdirs()
                 outputSourceDir.mkdirs()
                 val task = project.tasks.register(taskName, LayoutGeneratorTask::class.java) {
-                    it.layoutDirectory.set(layoutDirectory)
+                    it.containerLayoutDirectory.set(containerLayoutDirectory)
+                    it.childLayoutDirectory.set(childLayoutDirectory)
                     it.outputResourcesDir.set(outputResourcesDir)
                     it.outputSourceDir.set(outputSourceDir)
                 }
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotationConfigChangesActivityB.java b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/AlignmentModifier.kt
similarity index 69%
rename from appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotationConfigChangesActivityB.java
rename to glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/AlignmentModifier.kt
index 2886fbe..304c783 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotationConfigChangesActivityB.java
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/AlignmentModifier.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 The Android Open Source Project
+ * 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.
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-package androidx.appcompat.app;
+package androidx.glance.appwidget
 
-import androidx.activity.ComponentActivity;
+import androidx.glance.GlanceModifier
+import androidx.glance.layout.Alignment
 
-/**
- * An activity.
- */
-public class NightModeRotationConfigChangesActivityB extends ComponentActivity {}
+internal class AlignmentModifier(val alignment: Alignment) : GlanceModifier.Element
\ No newline at end of file
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/ApplyModifiers.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/ApplyModifiers.kt
index 33a27b7..c089b81 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/ApplyModifiers.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/ApplyModifiers.kt
@@ -94,6 +94,9 @@
                     )
                 }
             }
+            is AlignmentModifier -> {
+                // This modifier is handled somewhere else.
+            }
             else -> {
                 Log.w(GlanceAppWidgetTag, "Unknown modifier '$modifier', nothing done.")
             }
@@ -200,8 +203,9 @@
             "Using a width of $width requires a complex layout before API 31"
         )
     }
-    // Wrap and Expand are done in XML on Android S+
-    if (width in listOf(Dimension.Wrap, Dimension.Expand)) return
+    // Wrap and Expand are done in XML on Android S & Sv2
+    if (Build.VERSION.SDK_INT < 33 &&
+        width in listOf(Dimension.Wrap, Dimension.Expand)) return
     ApplyModifiersApi31Impl.setViewWidth(rv, viewId, width)
 }
 
@@ -229,8 +233,9 @@
             "Using a height of $height requires a complex layout before API 31"
         )
     }
-    // Wrap and Expand are done in XML on Android S+
-    if (height in listOf(Dimension.Wrap, Dimension.Expand)) return
+    // Wrap and Expand are done in XML on Android S & Sv2
+    if (Build.VERSION.SDK_INT < 33 &&
+        height in listOf(Dimension.Wrap, Dimension.Expand)) return
     ApplyModifiersApi31Impl.setViewHeight(rv, viewId, height)
 }
 
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/GlanceAppWidget.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/GlanceAppWidget.kt
index 80e1045..0ba075d 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/GlanceAppWidget.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/GlanceAppWidget.kt
@@ -199,11 +199,15 @@
         state: Any?,
         options: Bundle
     ): RemoteViews {
-        val layoutConfig = LayoutConfiguration.load(context, appWidgetId)
+        val layoutConfig = if (Build.VERSION.SDK_INT >= 33) {
+            null
+        } else {
+            LayoutConfiguration.load(context, appWidgetId)
+        }
         return try {
             compose(context, appWidgetManager, appWidgetId, state, options, layoutConfig)
         } finally {
-            layoutConfig.save()
+            layoutConfig?.save()
         }
     }
 
@@ -214,7 +218,7 @@
         appWidgetId: Int,
         state: Any?,
         options: Bundle,
-        layoutConfig: LayoutConfiguration,
+        layoutConfig: LayoutConfiguration?,
     ): RemoteViews =
         when (val localSizeMode = this.sizeMode) {
             is SizeMode.Single -> {
@@ -289,7 +293,7 @@
         appWidgetId: Int,
         state: Any?,
         options: Bundle,
-        layoutConfig: LayoutConfiguration,
+        layoutConfig: LayoutConfiguration?,
     ) = coroutineScope {
         val views =
             options.extractOrientationSizes()
@@ -331,7 +335,7 @@
         state: Any?,
         options: Bundle,
         sizes: Set<DpSize>,
-        layoutConfig: LayoutConfiguration,
+        layoutConfig: LayoutConfiguration?,
     ) = coroutineScope {
         // Find the best view, emulating what Android S+ would do.
         val orderedSizes = sizes.sortedBySize()
@@ -370,7 +374,7 @@
         state: Any?,
         options: Bundle,
         size: DpSize,
-        layoutConfig: LayoutConfiguration,
+        layoutConfig: LayoutConfiguration?,
     ): RemoteViews = withContext(BroadcastFrameClock()) {
         // The maximum depth must be reduced if the compositions are combined
         val root = RemoteViewsRoot(maxDepth = MaxComposeTreeDepth)
@@ -398,7 +402,7 @@
             appWidgetId,
             root,
             layoutConfig,
-            layoutConfig.addLayout(root),
+            layoutConfig?.addLayout(root) ?: 0,
             size
         )
     }
@@ -421,7 +425,7 @@
             state: Any?,
             options: Bundle,
             allSizes: Collection<DpSize>,
-            layoutConfig: LayoutConfiguration
+            layoutConfig: LayoutConfiguration?
         ): RemoteViews = coroutineScope {
             val allViews =
                 allSizes.map { size ->
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/LayoutSelection.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/LayoutSelection.kt
index ef8564ac..7a3c5fd 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/LayoutSelection.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/LayoutSelection.kt
@@ -20,8 +20,10 @@
 import android.view.View
 import android.view.ViewGroup
 import android.widget.RemoteViews
+import androidx.annotation.DoNotInline
 import androidx.annotation.IdRes
 import androidx.annotation.LayoutRes
+import androidx.annotation.RequiresApi
 import androidx.compose.ui.unit.dp
 import androidx.glance.GlanceModifier
 import androidx.glance.findModifier
@@ -68,6 +70,29 @@
 
 internal data class ContainerInfo(@LayoutRes val layoutId: Int)
 
+/**
+ * Box child selector.
+ *
+ * This class is used to select a layout with a particular alignment to be used as a child of
+ * Box.
+ */
+internal data class BoxChildSelector(
+    val type: LayoutType,
+    val horizontalAlignment: Alignment.Horizontal,
+    val verticalAlignment: Alignment.Vertical,
+)
+
+/**
+ * Selector for children of [Row] and [Column].
+ *
+ * This class is used to select a layout with layout_weight set / unset.
+ */
+internal data class RowColumnChildSelector(
+    val type: LayoutType,
+    val expandWidth: Boolean,
+    val expandHeight: Boolean,
+)
+
 /** Type of size needed for a layout. */
 internal enum class LayoutSize {
     Wrap,
@@ -167,6 +192,20 @@
     aliasIndex: Int
 ): RemoteViewsInfo {
     val context = translationContext.context
+    if (Build.VERSION.SDK_INT >= 33) {
+        return RemoteViewsInfo(
+            remoteViews = remoteViews(translationContext, FirstRootAlias).apply {
+                modifier.findModifier<WidthModifier>()?.let {
+                    applySimpleWidthModifier(context, this, it, R.id.rootView)
+                }
+                modifier.findModifier<HeightModifier>()?.let {
+                    applySimpleHeightModifier(context, this, it, R.id.rootView)
+                }
+                removeAllViews(R.id.rootView)
+            },
+            view = InsertedViewInfo(mainViewId = R.id.rootView)
+        )
+    }
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
         require(aliasIndex < RootAliasCount) {
             "Index of the root view cannot be more than $RootAliasCount, " +
@@ -186,7 +225,10 @@
                     applySimpleHeightModifier(context, this, it, R.id.rootView)
                 }
             },
-            view = InsertedViewInfo(children = mapOf(0 to mapOf(sizeSelector to R.id.rootStubId)))
+            view = InsertedViewInfo(
+                mainViewId = R.id.rootView,
+                children = mapOf(0 to mapOf(sizeSelector to R.id.rootStubId)),
+            )
         )
     }
     require(RootAliasTypeCount * aliasIndex < RootAliasCount) {
@@ -209,12 +251,45 @@
     )
 }
 
+@IdRes
+private fun selectLayout33(
+    type: LayoutType,
+    modifier: GlanceModifier,
+): Int? {
+    if (Build.VERSION.SDK_INT < 33) return null
+    val align = modifier.findModifier<AlignmentModifier>()
+    val expandWidth =
+        modifier.findModifier<WidthModifier>()?.let { it.width == Dimension.Expand } ?: false
+    val expandHeight =
+        modifier.findModifier<HeightModifier>()?.let { it.height == Dimension.Expand } ?: false
+    if (align != null) {
+        return generatedBoxChildren[BoxChildSelector(
+            type,
+            align.alignment.horizontal,
+            align.alignment.vertical,
+        )]?.layoutId
+            ?: throw IllegalArgumentException(
+                "Cannot find $type with alignment ${align.alignment}"
+            )
+    } else if (expandWidth || expandHeight) {
+        return generatedRowColumnChildren[RowColumnChildSelector(
+            type,
+            expandWidth,
+            expandHeight,
+        )]?.layoutId
+            ?: throw IllegalArgumentException("Cannot find $type with defaultWeight set")
+    } else {
+        return null
+    }
+}
+
 internal fun RemoteViews.insertView(
     translationContext: TranslationContext,
     type: LayoutType,
     modifier: GlanceModifier
 ): InsertedViewInfo {
-    val childLayout = LayoutMap[type]
+    val childLayout = selectLayout33(type, modifier)
+        ?: LayoutMap[type]
         ?: throw IllegalArgumentException("Cannot use `insertView` with a container like $type")
     return insertViewInternal(translationContext, childLayout, modifier)
 }
@@ -236,6 +311,16 @@
         }
         android.R.id.background
     }
+    if (Build.VERSION.SDK_INT >= 33) {
+        val viewId = specifiedViewId ?: translationContext.nextViewId()
+        val child = LayoutSelectionApi31Impl.remoteViews(
+            translationContext.context.packageName,
+            childLayout,
+            viewId,
+        )
+        addChildView(translationContext.parentContext.mainViewId, child, pos)
+        return InsertedViewInfo(mainViewId = viewId)
+    }
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
         val width = if (widthMod == Dimension.Expand) LayoutSize.Expand else LayoutSize.Wrap
         val height = if (heightMod == Dimension.Expand) LayoutSize.Expand else LayoutSize.Wrap
@@ -292,16 +377,17 @@
     horizontalAlignment: Alignment.Horizontal?,
     verticalAlignment: Alignment.Vertical?,
 ): InsertedViewInfo {
-    val childLayout = generatedContainers[ContainerSelector(
-        type,
-        numChildren,
-        horizontalAlignment,
-        verticalAlignment
-    )]
+    val childLayout = selectLayout33(type, modifier)
+        ?: generatedContainers[ContainerSelector(
+            type,
+            if (Build.VERSION.SDK_INT >= 33) 0 else numChildren,
+            horizontalAlignment,
+            verticalAlignment
+        )]?.layoutId
         ?: throw IllegalArgumentException("Cannot find container $type with $numChildren children")
     val childrenMapping = generatedChildren[type]
         ?: throw IllegalArgumentException("Cannot find generated children for $type")
-    return insertViewInternal(translationContext, childLayout.layoutId, modifier)
+    return insertViewInternal(translationContext, childLayout, modifier)
         .copy(children = childrenMapping)
 }
 
@@ -322,3 +408,13 @@
         else -> Dimension.Dp((sizePx / context.resources.displayMetrics.density).dp)
     }
 }
+
+@RequiresApi(Build.VERSION_CODES.S)
+private object LayoutSelectionApi31Impl {
+    @DoNotInline
+    fun remoteViews(
+        packageName: String,
+        @LayoutRes layoutId: Int,
+        viewId: Int
+    ) = RemoteViews(packageName, layoutId, viewId)
+}
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/RemoteViewsTranslator.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/RemoteViewsTranslator.kt
index 13c021f..f0e6933 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/RemoteViewsTranslator.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/RemoteViewsTranslator.kt
@@ -60,7 +60,7 @@
     context: Context,
     appWidgetId: Int,
     element: RemoteViewsRoot,
-    layoutConfiguration: LayoutConfiguration,
+    layoutConfiguration: LayoutConfiguration?,
     rootViewIndex: Int,
     layoutSize: DpSize,
 ) =
@@ -104,7 +104,7 @@
     val context: Context,
     val appWidgetId: Int,
     val isRtl: Boolean,
-    val layoutConfiguration: LayoutConfiguration,
+    val layoutConfiguration: LayoutConfiguration?,
     val itemPosition: Int,
     val isLazyCollectionDescendant: Boolean = false,
     val lastViewId: AtomicInteger = AtomicInteger(0),
@@ -228,6 +228,9 @@
         element.modifier,
         viewDef
     )
+    element.children.forEach {
+        it.modifier = it.modifier.then(AlignmentModifier(element.contentAlignment))
+    }
     setChildren(
         translationContext,
         viewDef,
@@ -256,7 +259,7 @@
     )
     setLinearLayoutGravity(
         viewDef.mainViewId,
-        element.horizontalAlignment.toGravity()
+        Alignment(element.horizontalAlignment, element.verticalAlignment).toGravity()
     )
     applyModifiers(
         translationContext.canUseSelectableGroup(),
@@ -293,7 +296,7 @@
     )
     setLinearLayoutGravity(
         viewDef.mainViewId,
-        element.verticalAlignment.toGravity()
+        Alignment(element.horizontalAlignment, element.verticalAlignment).toGravity()
     )
     applyModifiers(
         translationContext.canUseSelectableGroup(),
@@ -386,7 +389,7 @@
 /**
  * Add stable view if on Android S+, otherwise simply add the view.
  */
-private fun RemoteViews.addChildView(viewId: Int, childView: RemoteViews, stableId: Int) {
+internal fun RemoteViews.addChildView(viewId: Int, childView: RemoteViews, stableId: Int) {
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
         RemoteViewsTranslatorApi31Impl.addChildView(this, viewId, childView, stableId)
         return
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyListTranslator.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyListTranslator.kt
index 5e0f9c4..5dd29af 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyListTranslator.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyListTranslator.kt
@@ -79,7 +79,7 @@
                 translateComposition(
                     childContext.forLazyViewItem(position, LazyListItemStartingViewId),
                     listOf(itemEmittable),
-                    translationContext.layoutConfiguration.addLayout(itemEmittable),
+                    translationContext.layoutConfiguration?.addLayout(itemEmittable) ?: -1,
                 )
             )
             // If the user specifies any explicit ids, we assume the list to be stable
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt
index 7d727b0..84b359c 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/LazyVerticalGridTranslator.kt
@@ -89,7 +89,7 @@
                 translateComposition(
                     childContext.forLazyViewItem(position, LazyVerticalGridItemStartingViewId),
                     listOf(itemEmittable),
-                    translationContext.layoutConfiguration.addLayout(itemEmittable),
+                    translationContext.layoutConfiguration?.addLayout(itemEmittable) ?: -1,
                 )
             )
             // If the user specifies any explicit ids, we assume the list to be stable
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_button.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_button.xml
index 7594c00..9489e43 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_button.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_button.xml
@@ -15,6 +15,8 @@
   -->
 
 <Button xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     style="@style/Glance.AppWidget.Button"/>
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_check_box.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_check_box.xml
index af3d736..c23e6f4 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_check_box.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_check_box.xml
@@ -15,6 +15,8 @@
   -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:textDirection="locale"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_check_box_backport.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_check_box_backport.xml
index 3df83c2..b9d053c 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_check_box_backport.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_check_box_backport.xml
@@ -15,6 +15,8 @@
   -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:tag="glanceCompoundButton"
     style="@style/Glance.AppWidget.CheckBoxBackport"
     android:layout_width="wrap_content"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_circular_progress_indicator.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_circular_progress_indicator.xml
index 0bb1dae2d..5cd903d 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_circular_progress_indicator.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_circular_progress_indicator.xml
@@ -15,6 +15,8 @@
   -->
 
 <ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     style="@style/Glance.AppWidget.CircularProgressIndicator"/>
\ No newline at end of file
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_frame.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_frame.xml
index adfa3c0..37347b6 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_frame.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_frame.xml
@@ -15,5 +15,7 @@
   -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="match_parent"
     android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_image_crop.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_image_crop.xml
index 0e0b278..d635cb6 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_image_crop.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_image_crop.xml
@@ -15,6 +15,8 @@
   -->
 
 <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:scaleType="centerCrop" />
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_image_fill_bounds.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_image_fill_bounds.xml
index 107dd70..786ab91 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_image_fill_bounds.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_image_fill_bounds.xml
@@ -15,6 +15,8 @@
   -->
 
 <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:scaleType="fitXY" />
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_image_fit.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_image_fit.xml
index 8f7b4ba..97740bb 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_image_fit.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_image_fit.xml
@@ -15,6 +15,8 @@
   -->
 
 <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:scaleType="fitCenter" />
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_linear_progress_indicator.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_linear_progress_indicator.xml
index 918ac5c..775ca38 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_linear_progress_indicator.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_linear_progress_indicator.xml
@@ -15,6 +15,8 @@
   -->
 
 <ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     style="@style/Glance.AppWidget.LinearProgressIndicator"/>
\ No newline at end of file
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_list.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_list.xml
index 9758a8a9..fe0fa2d 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_list.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_list.xml
@@ -15,6 +15,8 @@
   -->
 
 <ListView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:divider="@null"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_radio_button.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_radio_button.xml
index 6a3cbd9..718a865 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_radio_button.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_radio_button.xml
@@ -15,6 +15,8 @@
   -->
 
 <RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:tag="glanceCompoundButton"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_radio_button_backport.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_radio_button_backport.xml
index 1ca712d..3499fec 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_radio_button_backport.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_radio_button_backport.xml
@@ -15,6 +15,8 @@
 -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:tag="glanceCompoundButton"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_swtch.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_swtch.xml
index c5780e5..931c1fb 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_swtch.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_swtch.xml
@@ -15,6 +15,8 @@
   -->
 
 <Switch xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:tag="glanceCompoundButton"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_swtch_backport.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_swtch_backport.xml
index 6c34960..ac71093 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_swtch_backport.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_swtch_backport.xml
@@ -15,6 +15,8 @@
   -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:tag="glanceCompoundButton"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_text.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_text.xml
index d04f6ac..04cb0ea 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_text.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_text.xml
@@ -15,6 +15,8 @@
   -->
 
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:textDirection="locale"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_auto_fit.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_auto_fit.xml
index bc9f7e45..090f44c0 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_auto_fit.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_auto_fit.xml
@@ -15,6 +15,8 @@
   -->
 
 <GridView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:divider="@null"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_five_columns.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_five_columns.xml
index d4eb3d0..55d7461 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_five_columns.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_five_columns.xml
@@ -15,6 +15,8 @@
   -->
 
 <GridView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:divider="@null"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_four_columns.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_four_columns.xml
index c5779a6..662fdd4 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_four_columns.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_four_columns.xml
@@ -15,6 +15,8 @@
   -->
 
 <GridView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:divider="@null"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_one_column.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_one_column.xml
index 130b429..9d2b48f0 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_one_column.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_one_column.xml
@@ -15,6 +15,8 @@
   -->
 
 <GridView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:divider="@null"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_three_columns.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_three_columns.xml
index 226862ec..a8ef7e9 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_three_columns.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_three_columns.xml
@@ -15,6 +15,8 @@
   -->
 
 <GridView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:divider="@null"
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_two_columns.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_two_columns.xml
index 5243b80..73b745d 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_two_columns.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_vertical_grid_two_columns.xml
@@ -15,6 +15,8 @@
   -->
 
 <GridView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:divider="@null"
diff --git a/glance/glance-appwidget/src/androidMain/res/values/attrs.xml b/glance/glance-appwidget/src/androidMain/res/values/attrs.xml
new file mode 100644
index 0000000..82db37a
--- /dev/null
+++ b/glance/glance-appwidget/src/androidMain/res/values/attrs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <declare-styleable name="GlanceAppWidget">
+	    <attr name="glance_isTopLevelLayout" format="boolean" />
+    </declare-styleable>
+</resources>
diff --git a/health/health-connect-client/api/current.txt b/health/health-connect-client/api/current.txt
index 6ae53ca..1840826 100644
--- a/health/health-connect-client/api/current.txt
+++ b/health/health-connect-client/api/current.txt
@@ -135,15 +135,15 @@
   }
 
   public final class BasalBodyTemperatureRecord implements androidx.health.connect.client.records.Record {
-    ctor public BasalBodyTemperatureRecord(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public BasalBodyTemperatureRecord(androidx.health.connect.client.units.Temperature temperature, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public String? getMeasurementLocation();
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public double getTemperatureDegreesCelsius();
+    method public androidx.health.connect.client.units.Temperature getTemperature();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final String? measurementLocation;
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final double temperatureDegreesCelsius;
+    property public final androidx.health.connect.client.units.Temperature temperature;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -264,15 +264,15 @@
   }
 
   public final class BodyTemperatureRecord implements androidx.health.connect.client.records.Record {
-    ctor public BodyTemperatureRecord(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public BodyTemperatureRecord(androidx.health.connect.client.units.Temperature temperature, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public String? getMeasurementLocation();
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public double getTemperatureDegreesCelsius();
+    method public androidx.health.connect.client.units.Temperature getTemperature();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final String? measurementLocation;
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final double temperatureDegreesCelsius;
+    property public final androidx.health.connect.client.units.Temperature temperature;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -1435,5 +1435,24 @@
   public final class LengthKt {
   }
 
+  public final class Temperature implements java.lang.Comparable<androidx.health.connect.client.units.Temperature> {
+    method public static androidx.health.connect.client.units.Temperature celsius(double value);
+    method public int compareTo(androidx.health.connect.client.units.Temperature other);
+    method public static androidx.health.connect.client.units.Temperature fahrenheit(double value);
+    method public double getCelsius();
+    method public double getFahrenheit();
+    property public final double inCelsius;
+    property public final double inFahrenheit;
+    field public static final androidx.health.connect.client.units.Temperature.Companion Companion;
+  }
+
+  public static final class Temperature.Companion {
+    method public androidx.health.connect.client.units.Temperature celsius(double value);
+    method public androidx.health.connect.client.units.Temperature fahrenheit(double value);
+  }
+
+  public final class TemperatureKt {
+  }
+
 }
 
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 6ae53ca..1840826 100644
--- a/health/health-connect-client/api/public_plus_experimental_current.txt
+++ b/health/health-connect-client/api/public_plus_experimental_current.txt
@@ -135,15 +135,15 @@
   }
 
   public final class BasalBodyTemperatureRecord implements androidx.health.connect.client.records.Record {
-    ctor public BasalBodyTemperatureRecord(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public BasalBodyTemperatureRecord(androidx.health.connect.client.units.Temperature temperature, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public String? getMeasurementLocation();
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public double getTemperatureDegreesCelsius();
+    method public androidx.health.connect.client.units.Temperature getTemperature();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final String? measurementLocation;
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final double temperatureDegreesCelsius;
+    property public final androidx.health.connect.client.units.Temperature temperature;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -264,15 +264,15 @@
   }
 
   public final class BodyTemperatureRecord implements androidx.health.connect.client.records.Record {
-    ctor public BodyTemperatureRecord(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public BodyTemperatureRecord(androidx.health.connect.client.units.Temperature temperature, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public String? getMeasurementLocation();
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public double getTemperatureDegreesCelsius();
+    method public androidx.health.connect.client.units.Temperature getTemperature();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final String? measurementLocation;
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final double temperatureDegreesCelsius;
+    property public final androidx.health.connect.client.units.Temperature temperature;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -1435,5 +1435,24 @@
   public final class LengthKt {
   }
 
+  public final class Temperature implements java.lang.Comparable<androidx.health.connect.client.units.Temperature> {
+    method public static androidx.health.connect.client.units.Temperature celsius(double value);
+    method public int compareTo(androidx.health.connect.client.units.Temperature other);
+    method public static androidx.health.connect.client.units.Temperature fahrenheit(double value);
+    method public double getCelsius();
+    method public double getFahrenheit();
+    property public final double inCelsius;
+    property public final double inFahrenheit;
+    field public static final androidx.health.connect.client.units.Temperature.Companion Companion;
+  }
+
+  public static final class Temperature.Companion {
+    method public androidx.health.connect.client.units.Temperature celsius(double value);
+    method public androidx.health.connect.client.units.Temperature fahrenheit(double value);
+  }
+
+  public final class TemperatureKt {
+  }
+
 }
 
diff --git a/health/health-connect-client/api/restricted_current.txt b/health/health-connect-client/api/restricted_current.txt
index 62cb922..6bd0c2c 100644
--- a/health/health-connect-client/api/restricted_current.txt
+++ b/health/health-connect-client/api/restricted_current.txt
@@ -135,15 +135,15 @@
   }
 
   public final class BasalBodyTemperatureRecord implements androidx.health.connect.client.records.InstantaneousRecord {
-    ctor public BasalBodyTemperatureRecord(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public BasalBodyTemperatureRecord(androidx.health.connect.client.units.Temperature temperature, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public String? getMeasurementLocation();
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public double getTemperatureDegreesCelsius();
+    method public androidx.health.connect.client.units.Temperature getTemperature();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final String? measurementLocation;
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final double temperatureDegreesCelsius;
+    property public final androidx.health.connect.client.units.Temperature temperature;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -264,15 +264,15 @@
   }
 
   public final class BodyTemperatureRecord implements androidx.health.connect.client.records.InstantaneousRecord {
-    ctor public BodyTemperatureRecord(double temperatureDegreesCelsius, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
+    ctor public BodyTemperatureRecord(androidx.health.connect.client.units.Temperature temperature, optional String? measurementLocation, java.time.Instant time, java.time.ZoneOffset? zoneOffset, optional androidx.health.connect.client.records.metadata.Metadata metadata);
     method public String? getMeasurementLocation();
     method public androidx.health.connect.client.records.metadata.Metadata getMetadata();
-    method public double getTemperatureDegreesCelsius();
+    method public androidx.health.connect.client.units.Temperature getTemperature();
     method public java.time.Instant getTime();
     method public java.time.ZoneOffset? getZoneOffset();
     property public final String? measurementLocation;
     property public androidx.health.connect.client.records.metadata.Metadata metadata;
-    property public final double temperatureDegreesCelsius;
+    property public final androidx.health.connect.client.units.Temperature temperature;
     property public java.time.Instant time;
     property public java.time.ZoneOffset? zoneOffset;
   }
@@ -1458,5 +1458,24 @@
   public final class LengthKt {
   }
 
+  public final class Temperature implements java.lang.Comparable<androidx.health.connect.client.units.Temperature> {
+    method public static androidx.health.connect.client.units.Temperature celsius(double value);
+    method public int compareTo(androidx.health.connect.client.units.Temperature other);
+    method public static androidx.health.connect.client.units.Temperature fahrenheit(double value);
+    method public double getCelsius();
+    method public double getFahrenheit();
+    property public final double inCelsius;
+    property public final double inFahrenheit;
+    field public static final androidx.health.connect.client.units.Temperature.Companion Companion;
+  }
+
+  public static final class Temperature.Companion {
+    method public androidx.health.connect.client.units.Temperature celsius(double value);
+    method public androidx.health.connect.client.units.Temperature fahrenheit(double value);
+  }
+
+  public final class TemperatureKt {
+  }
+
 }
 
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/RecordsTypeNameMap.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/RecordsTypeNameMap.kt
index 61677c8..3bc468f 100644
--- a/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/RecordsTypeNameMap.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/impl/converters/datatype/RecordsTypeNameMap.kt
@@ -19,7 +19,6 @@
 
 import androidx.annotation.RestrictTo
 import androidx.health.connect.client.records.ActiveCaloriesBurnedRecord
-import androidx.health.connect.client.records.ActiveEnergyBurnedRecord
 import androidx.health.connect.client.records.BasalBodyTemperatureRecord
 import androidx.health.connect.client.records.BasalMetabolicRateRecord
 import androidx.health.connect.client.records.BloodGlucoseRecord
@@ -67,7 +66,6 @@
 import androidx.health.connect.client.records.StepsRecord
 import androidx.health.connect.client.records.SwimmingStrokesRecord
 import androidx.health.connect.client.records.TotalCaloriesBurnedRecord
-import androidx.health.connect.client.records.TotalEnergyBurnedRecord
 import androidx.health.connect.client.records.Vo2MaxRecord
 import androidx.health.connect.client.records.WaistCircumferenceRecord
 import androidx.health.connect.client.records.WeightRecord
@@ -77,7 +75,6 @@
 val RECORDS_TYPE_NAME_MAP: Map<String, KClass<out Record>> =
     mapOf(
         "ActiveCaloriesBurned" to ActiveCaloriesBurnedRecord::class,
-        "ActiveEnergyBurned" to ActiveEnergyBurnedRecord::class,
         "ActivityEvent" to ExerciseEventRecord::class, // Keep legacy Activity name
         "ActivityLap" to ExerciseLapRecord::class, // Keep legacy Activity name
         "ActivitySession" to ExerciseSessionRecord::class, // Keep legacy Activity name
@@ -126,7 +123,6 @@
         "StepsCadenceSeries" to StepsCadenceRecord::class, // Keep legacy Series suffix
         "SwimmingStrokes" to SwimmingStrokesRecord::class,
         "TotalCaloriesBurned" to TotalCaloriesBurnedRecord::class,
-        "TotalEnergyBurned" to TotalEnergyBurnedRecord::class,
         "Vo2Max" to Vo2MaxRecord::class,
         "WaistCircumference" to WaistCircumferenceRecord::class,
         "WheelchairPushes" to WheelchairPushesRecord::class,
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 f533b67..317f450 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
@@ -19,7 +19,6 @@
 
 import androidx.annotation.RestrictTo
 import androidx.health.connect.client.records.ActiveCaloriesBurnedRecord
-import androidx.health.connect.client.records.ActiveEnergyBurnedRecord
 import androidx.health.connect.client.records.BasalBodyTemperatureRecord
 import androidx.health.connect.client.records.BasalMetabolicRateRecord
 import androidx.health.connect.client.records.BloodGlucoseRecord
@@ -72,11 +71,11 @@
 import androidx.health.connect.client.records.StepsRecord
 import androidx.health.connect.client.records.SwimmingStrokesRecord
 import androidx.health.connect.client.records.TotalCaloriesBurnedRecord
-import androidx.health.connect.client.records.TotalEnergyBurnedRecord
 import androidx.health.connect.client.records.Vo2MaxRecord
 import androidx.health.connect.client.records.WaistCircumferenceRecord
 import androidx.health.connect.client.records.WeightRecord
 import androidx.health.connect.client.records.WheelchairPushesRecord
+import androidx.health.connect.client.units.celsius
 import androidx.health.connect.client.units.meters
 import androidx.health.platform.client.proto.DataProto
 import java.time.Instant
@@ -87,7 +86,7 @@
         when (dataType.name) {
             "BasalBodyTemperature" ->
                 BasalBodyTemperatureRecord(
-                    temperatureDegreesCelsius = getDouble("temperature"),
+                    temperature = getDouble("temperature").celsius,
                     measurementLocation = getEnum("measurementLocation"),
                     time = time,
                     zoneOffset = zoneOffset,
@@ -129,7 +128,7 @@
                 )
             "BodyTemperature" ->
                 BodyTemperatureRecord(
-                    temperatureDegreesCelsius = getDouble("temperature"),
+                    temperature = getDouble("temperature").celsius,
                     measurementLocation = getEnum("measurementLocation"),
                     time = time,
                     zoneOffset = zoneOffset,
@@ -389,15 +388,6 @@
                     endZoneOffset = endZoneOffset,
                     metadata = metadata
                 )
-            "ActiveEnergyBurned" ->
-                ActiveEnergyBurnedRecord(
-                    energyKcal = getDouble("energy"),
-                    startTime = startTime,
-                    startZoneOffset = startZoneOffset,
-                    endTime = endTime,
-                    endZoneOffset = endZoneOffset,
-                    metadata = metadata
-                )
             "ActivityEvent" ->
                 ExerciseEventRecord(
                     eventType = getEnum("eventType") ?: "",
@@ -572,15 +562,6 @@
                     endZoneOffset = endZoneOffset,
                     metadata = metadata
                 )
-            "TotalEnergyBurned" ->
-                TotalEnergyBurnedRecord(
-                    energyKcal = getDouble("energy"),
-                    startTime = startTime,
-                    startZoneOffset = startZoneOffset,
-                    endTime = endTime,
-                    endZoneOffset = endZoneOffset,
-                    metadata = metadata
-                )
             "WheelchairPushes" ->
                 WheelchairPushesRecord(
                     count = getLong("count"),
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 8412414..86e7d00 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
@@ -19,7 +19,6 @@
 
 import androidx.annotation.RestrictTo
 import androidx.health.connect.client.records.ActiveCaloriesBurnedRecord
-import androidx.health.connect.client.records.ActiveEnergyBurnedRecord
 import androidx.health.connect.client.records.BasalBodyTemperatureRecord
 import androidx.health.connect.client.records.BasalMetabolicRateRecord
 import androidx.health.connect.client.records.BloodGlucoseRecord
@@ -68,7 +67,6 @@
 import androidx.health.connect.client.records.StepsRecord
 import androidx.health.connect.client.records.SwimmingStrokesRecord
 import androidx.health.connect.client.records.TotalCaloriesBurnedRecord
-import androidx.health.connect.client.records.TotalEnergyBurnedRecord
 import androidx.health.connect.client.records.Vo2MaxRecord
 import androidx.health.connect.client.records.WaistCircumferenceRecord
 import androidx.health.connect.client.records.WeightRecord
@@ -82,7 +80,7 @@
             instantaneousProto()
                 .setDataType(protoDataType("BasalBodyTemperature"))
                 .apply {
-                    putValues("temperature", doubleVal(temperatureDegreesCelsius))
+                    putValues("temperature", doubleVal(temperature.inCelsius))
                     measurementLocation?.let { putValues("measurementLocation", enumVal(it)) }
                 }
                 .build()
@@ -120,7 +118,7 @@
             instantaneousProto()
                 .setDataType(protoDataType("BodyTemperature"))
                 .apply {
-                    putValues("temperature", doubleVal(temperatureDegreesCelsius))
+                    putValues("temperature", doubleVal(temperature.inCelsius))
                     measurementLocation?.let { putValues("measurementLocation", enumVal(it)) }
                 }
                 .build()
@@ -290,11 +288,6 @@
                 .setDataType(protoDataType("ActiveCaloriesBurned"))
                 .apply { putValues("energy", doubleVal(energyKcal)) }
                 .build()
-        is ActiveEnergyBurnedRecord ->
-            intervalProto()
-                .setDataType(protoDataType("ActiveEnergyBurned"))
-                .apply { putValues("energy", doubleVal(energyKcal)) }
-                .build()
         is ExerciseEventRecord ->
             intervalProto()
                 .setDataType(protoDataType("ActivityEvent"))
@@ -513,11 +506,6 @@
                 .setDataType(protoDataType("TotalCaloriesBurned"))
                 .apply { putValues("energy", doubleVal(energyKcal)) }
                 .build()
-        is TotalEnergyBurnedRecord ->
-            intervalProto()
-                .setDataType(protoDataType("TotalEnergyBurned"))
-                .apply { putValues("energy", doubleVal(energyKcal)) }
-                .build()
         is WheelchairPushesRecord ->
             intervalProto()
                 .setDataType(protoDataType("WheelchairPushes"))
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActiveEnergyBurnedRecord.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActiveEnergyBurnedRecord.kt
deleted file mode 100644
index 3508f0d..0000000
--- a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/ActiveEnergyBurnedRecord.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.health.connect.client.records
-
-import androidx.annotation.RestrictTo
-import androidx.health.connect.client.records.metadata.Metadata
-import java.time.Instant
-import java.time.ZoneOffset
-
-/**
- * Captures the estimated active energy burned by the user (in kilocalories), excluding basal
- * metabolic rate (BMR). Each record represents the total kilocalories burned over a time interval,
- * so both the start and end times should be set.
- *
- * @suppress
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-public class ActiveEnergyBurnedRecord(
-    /** Energy in kilocalories. Required field. Valid range: 0-1000000. */
-    public val energyKcal: Double,
-    override val startTime: Instant,
-    override val startZoneOffset: ZoneOffset?,
-    override val endTime: Instant,
-    override val endZoneOffset: ZoneOffset?,
-    override val metadata: Metadata = Metadata.EMPTY,
-) : IntervalRecord {
-    override fun equals(other: Any?): Boolean {
-        if (this === other) return true
-        if (other !is ActiveEnergyBurnedRecord) return false
-
-        if (energyKcal != other.energyKcal) return false
-        if (startTime != other.startTime) return false
-        if (startZoneOffset != other.startZoneOffset) return false
-        if (endTime != other.endTime) return false
-        if (endZoneOffset != other.endZoneOffset) return false
-        if (metadata != other.metadata) return false
-
-        return true
-    }
-
-    override fun hashCode(): Int {
-        var result = 0
-        result = 31 * result + energyKcal.hashCode()
-        result = 31 * result + (startZoneOffset?.hashCode() ?: 0)
-        result = 31 * result + endTime.hashCode()
-        result = 31 * result + (endZoneOffset?.hashCode() ?: 0)
-        result = 31 * result + metadata.hashCode()
-        return result
-    }
-}
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BasalBodyTemperatureRecord.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BasalBodyTemperatureRecord.kt
index 62af12e..725dd3c 100644
--- a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BasalBodyTemperatureRecord.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BasalBodyTemperatureRecord.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.Temperature
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -25,8 +26,8 @@
  * body temperature measurement.
  */
 public class BasalBodyTemperatureRecord(
-    /** Temperature in degrees Celsius. Required field. Valid range: 0-100. */
-    public val temperatureDegreesCelsius: Double,
+    /** Temperature in [Temperature] unit. Required field. Valid range: 0-100 Celsius degrees. */
+    public val temperature: Temperature,
     /**
      * Where on the user's basal body the temperature measurement was taken from. Optional field.
      * Allowed values: [BodyTemperatureMeasurementLocations].
@@ -37,15 +38,14 @@
     override val metadata: Metadata = Metadata.EMPTY,
 ) : InstantaneousRecord {
 
-    init {
-        requireNonNegative(value = temperatureDegreesCelsius, name = "temperatureDegreesCelsius")
-    }
-
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (other !is BasalBodyTemperatureRecord) return false
 
-        if (temperatureDegreesCelsius != other.temperatureDegreesCelsius) return false
+        if (temperature != other.temperature) return false
         if (measurementLocation != other.measurementLocation) return false
         if (time != other.time) return false
         if (zoneOffset != other.zoneOffset) return false
@@ -54,10 +54,12 @@
         return true
     }
 
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
     override fun hashCode(): Int {
-        var result = 0
-        result = 31 * result + temperatureDegreesCelsius.hashCode()
-        result = 31 * result + measurementLocation.hashCode()
+        var result = temperature.hashCode()
+        result = 31 * result + (measurementLocation?.hashCode() ?: 0)
         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/BodyTemperatureRecord.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyTemperatureRecord.kt
index a3ceda2..d2ca611 100644
--- a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyTemperatureRecord.kt
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/BodyTemperatureRecord.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.Temperature
 import java.time.Instant
 import java.time.ZoneOffset
 
@@ -24,8 +25,8 @@
  * temperature measurement.
  */
 public class BodyTemperatureRecord(
-    /** Temperature in degrees Celsius. Required field. Valid range: 0-100. */
-    public val temperatureDegreesCelsius: Double,
+    /** Temperature in [Temperature] unit. Required field. Valid range: 0-100 Celsius degrees. */
+    public val temperature: Temperature,
     /**
      * Where on the user's body the temperature measurement was taken from. Optional field. Allowed
      * values: [BodyTemperatureMeasurementLocations].
@@ -36,15 +37,14 @@
     override val metadata: Metadata = Metadata.EMPTY,
 ) : InstantaneousRecord {
 
-    init {
-        requireNonNegative(value = temperatureDegreesCelsius, name = "temperatureDegreesCelsius")
-    }
-
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (other !is BodyTemperatureRecord) return false
 
-        if (temperatureDegreesCelsius != other.temperatureDegreesCelsius) return false
+        if (temperature != other.temperature) return false
         if (measurementLocation != other.measurementLocation) return false
         if (time != other.time) return false
         if (zoneOffset != other.zoneOffset) return false
@@ -53,10 +53,12 @@
         return true
     }
 
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
     override fun hashCode(): Int {
-        var result = 0
-        result = 31 * result + temperatureDegreesCelsius.hashCode()
-        result = 31 * result + measurementLocation.hashCode()
+        var result = temperature.hashCode()
+        result = 31 * result + (measurementLocation?.hashCode() ?: 0)
         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/TotalEnergyBurnedRecord.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/records/TotalEnergyBurnedRecord.kt
deleted file mode 100644
index 8c6050e..0000000
--- a/health/health-connect-client/src/main/java/androidx/health/connect/client/records/TotalEnergyBurnedRecord.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package androidx.health.connect.client.records
-
-import androidx.annotation.RestrictTo
-import androidx.health.connect.client.aggregate.AggregateMetric
-import androidx.health.connect.client.records.metadata.Metadata
-import java.time.Instant
-import java.time.ZoneOffset
-
-/**
- * Total energy burned by the user (in kilocalories), including active & basal energy burned (BMR).
- * Each record represents the total kilocalories burned over a time interval.
- *
- * @suppress
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-public class TotalEnergyBurnedRecord(
-    /** Energy in kilocalories. Required field. Valid range: 0-1000000. */
-    public val energyKcal: Double,
-    override val startTime: Instant,
-    override val startZoneOffset: ZoneOffset?,
-    override val endTime: Instant,
-    override val endZoneOffset: ZoneOffset?,
-    override val metadata: Metadata = Metadata.EMPTY,
-) : IntervalRecord {
-    override fun equals(other: Any?): Boolean {
-        if (this === other) return true
-        if (other !is TotalEnergyBurnedRecord) return false
-
-        if (energyKcal != other.energyKcal) return false
-        if (startTime != other.startTime) return false
-        if (startZoneOffset != other.startZoneOffset) return false
-        if (endTime != other.endTime) return false
-        if (endZoneOffset != other.endZoneOffset) return false
-        if (metadata != other.metadata) return false
-
-        return true
-    }
-
-    override fun hashCode(): Int {
-        var result = 0
-        result = 31 * result + energyKcal.hashCode()
-        result = 31 * result + (startZoneOffset?.hashCode() ?: 0)
-        result = 31 * result + endTime.hashCode()
-        result = 31 * result + (endZoneOffset?.hashCode() ?: 0)
-        result = 31 * result + metadata.hashCode()
-        return result
-    }
-
-    companion object {
-        /**
-         * Metric identifier to retrieve total energy from
-         * [androidx.health.connect.client.aggregate.AggregationResult].
-         */
-        @JvmField
-        val TOTAL: AggregateMetric<Double> =
-            AggregateMetric.doubleMetric(
-                "TotalEnergyBurned",
-                AggregateMetric.AggregationType.TOTAL,
-                "energy"
-            )
-    }
-}
diff --git a/health/health-connect-client/src/main/java/androidx/health/connect/client/units/Temperature.kt b/health/health-connect-client/src/main/java/androidx/health/connect/client/units/Temperature.kt
new file mode 100644
index 0000000..5a1d80e
--- /dev/null
+++ b/health/health-connect-client/src/main/java/androidx/health/connect/client/units/Temperature.kt
@@ -0,0 +1,136 @@
+/*
+ * 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 temperature. Supported units:
+ *
+ * - Celsius - see [Temperature.celsius], [Double.celsius]
+ * - Fahrenheit - see [Temperature.fahrenheit], [Double.fahrenheit]
+ **/
+class Temperature private constructor(
+    private val value: Double,
+    private val type: Type,
+) : Comparable<Temperature> {
+
+    /** Returns the temperature in Celsius degrees. */
+    @get:JvmName("getCelsius")
+    val inCelsius: Double
+        get() =
+            when (type) {
+                Type.CELSIUS -> value
+                Type.FAHRENHEIT -> (value - 32.0) / 1.8
+            }
+
+    /** Returns the temperature in Fahrenheit degrees. */
+    @get:JvmName("getFahrenheit")
+    val inFahrenheit: Double
+        get() =
+            when (type) {
+                Type.CELSIUS -> value * 1.8 + 32.0
+                Type.FAHRENHEIT -> value
+            }
+
+    override fun compareTo(other: Temperature): Int =
+        if (type == other.type) {
+            value.compareTo(other.value)
+        } else {
+            inCelsius.compareTo(other.inCelsius)
+        }
+
+    /*
+     * Generated by the IDE: Code -> Generate -> "equals() and hashCode()".
+     */
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other !is Temperature) 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 {
+        /** Creates [Temperature] with the specified value in Celsius degrees. */
+        @JvmStatic fun celsius(value: Double): Temperature = Temperature(value, Type.CELSIUS)
+
+        /** Creates [Temperature] with the specified value in Fahrenheit degrees. */
+        @JvmStatic fun fahrenheit(value: Double): Temperature = Temperature(value, Type.FAHRENHEIT)
+    }
+
+    private enum class Type {
+        CELSIUS {
+            override val title: String = "Celsius"
+        },
+        FAHRENHEIT {
+            override val title: String = "Fahrenheit"
+        };
+
+        abstract val title: String
+    }
+}
+
+/** Creates [Temperature] with the specified value in Celsius degrees. */
+@get:JvmSynthetic
+val Double.celsius: Temperature
+    get() = Temperature.celsius(value = this)
+
+/** Creates [Temperature] with the specified value in Celsius degrees. */
+@get:JvmSynthetic
+val Long.celsius: Temperature
+    get() = toDouble().celsius
+
+/** Creates [Temperature] with the specified value in Celsius degrees. */
+@get:JvmSynthetic
+val Float.celsius: Temperature
+    get() = toDouble().celsius
+
+/** Creates [Temperature] with the specified value in Celsius degrees. */
+@get:JvmSynthetic
+val Int.celsius: Temperature
+    get() = toDouble().celsius
+
+/** Creates [Temperature] with the specified value in Fahrenheit degrees. */
+@get:JvmSynthetic
+val Double.fahrenheit: Temperature
+    get() = Temperature.fahrenheit(value = this)
+
+/** Creates [Temperature] with the specified value in Fahrenheit degrees. */
+@get:JvmSynthetic
+val Long.fahrenheit: Temperature
+    get() = toDouble().fahrenheit
+
+/** Creates [Temperature] with the specified value in Fahrenheit degrees. */
+@get:JvmSynthetic
+val Float.fahrenheit: Temperature
+    get() = toDouble().fahrenheit
+
+/** Creates [Temperature] with the specified value in Fahrenheit degrees. */
+@get:JvmSynthetic
+val Int.fahrenheit: Temperature
+    get() = toDouble().fahrenheit
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 eb372ab..a7a6e1a 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
@@ -17,7 +17,6 @@
 
 import androidx.health.connect.client.impl.converters.datatype.toDataTypeName
 import androidx.health.connect.client.records.ActiveCaloriesBurnedRecord
-import androidx.health.connect.client.records.ActiveEnergyBurnedRecord
 import androidx.health.connect.client.records.BasalBodyTemperatureRecord
 import androidx.health.connect.client.records.BasalMetabolicRateRecord
 import androidx.health.connect.client.records.BloodGlucoseRecord
@@ -79,7 +78,6 @@
 import androidx.health.connect.client.records.SwimmingStrokesRecord
 import androidx.health.connect.client.records.SwimmingStrokesRecord.SwimmingType
 import androidx.health.connect.client.records.TotalCaloriesBurnedRecord
-import androidx.health.connect.client.records.TotalEnergyBurnedRecord
 import androidx.health.connect.client.records.Vo2MaxRecord
 import androidx.health.connect.client.records.WaistCircumferenceRecord
 import androidx.health.connect.client.records.WeightRecord
@@ -87,6 +85,7 @@
 import androidx.health.connect.client.records.metadata.DataOrigin
 import androidx.health.connect.client.records.metadata.Device
 import androidx.health.connect.client.records.metadata.Metadata
+import androidx.health.connect.client.units.celsius
 import androidx.health.connect.client.units.meters
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
@@ -120,7 +119,7 @@
     fun testBasalBodyTemperature() {
         val dataOnlyRequired =
             BasalBodyTemperatureRecord(
-                temperatureDegreesCelsius = 1.0,
+                temperature = 1.celsius,
                 measurementLocation = null,
                 time = START_TIME,
                 zoneOffset = END_ZONE_OFFSET,
@@ -129,7 +128,7 @@
 
         val dataAllFields =
             BasalBodyTemperatureRecord(
-                temperatureDegreesCelsius = 1.0,
+                temperature = 1.celsius,
                 measurementLocation = BodyTemperatureMeasurementLocation.ARMPIT,
                 time = START_TIME,
                 zoneOffset = END_ZONE_OFFSET,
@@ -207,7 +206,7 @@
     fun testBodyTemperature() {
         val data =
             BodyTemperatureRecord(
-                temperatureDegreesCelsius = 1.0,
+                temperature = 1.celsius,
                 measurementLocation = null,
                 time = START_TIME,
                 zoneOffset = END_ZONE_OFFSET,
@@ -707,22 +706,6 @@
     }
 
     @Test
-    fun testActiveEnergyBurned() {
-        val data =
-            ActiveEnergyBurnedRecord(
-                energyKcal = 1.0,
-                startTime = START_TIME,
-                startZoneOffset = START_ZONE_OFFSET,
-                endTime = END_TIME,
-                endZoneOffset = END_ZONE_OFFSET,
-                metadata = TEST_METADATA
-            )
-
-        checkProtoAndRecordTypeNameMatch(data)
-        assertThat(toRecord(data.toProto())).isEqualTo(data)
-    }
-
-    @Test
     fun testActivityEvent() {
         val data =
             ExerciseEventRecord(
@@ -995,22 +978,6 @@
     }
 
     @Test
-    fun testTotalEnergyBurned() {
-        val data =
-            TotalEnergyBurnedRecord(
-                energyKcal = 1.0,
-                startTime = START_TIME,
-                startZoneOffset = START_ZONE_OFFSET,
-                endTime = END_TIME,
-                endZoneOffset = END_ZONE_OFFSET,
-                metadata = TEST_METADATA
-            )
-
-        checkProtoAndRecordTypeNameMatch(data)
-        assertThat(toRecord(data.toProto())).isEqualTo(data)
-    }
-
-    @Test
     fun testWheelchairPushes() {
         val data =
             WheelchairPushesRecord(
diff --git a/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallOnCast.java b/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallOnCast.java
new file mode 100644
index 0000000..c3d7f33
--- /dev/null
+++ b/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallOnCast.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+import android.os.Build;
+import android.view.DisplayCutout;
+
+/**
+ * Test class containing unsafe reference on cast object.
+ */
+@SuppressWarnings("unused")
+public class AutofixUnsafeCallOnCast {
+    /**
+     * Method making unsafe reference on cast object.
+     */
+    public void unsafeReferenceOnCastObject(Object secretDisplayCutout) {
+        if (Build.VERSION.SDK_INT >= 28) {
+            ((DisplayCutout) secretDisplayCutout).getSafeInsetTop();
+        }
+    }
+}
diff --git a/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallToThis.java b/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallToThis.java
new file mode 100644
index 0000000..6697751
--- /dev/null
+++ b/lint-checks/integration-tests/src/main/java/androidx/AutofixUnsafeCallToThis.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import android.os.Build;
+import android.view.ViewGroup;
+
+/**
+ * Test class containing unsafe references to a parent's instance method.
+ */
+@SuppressWarnings("unused")
+public abstract class AutofixUnsafeCallToThis extends ViewGroup {
+    /*
+     * Constructor to prevent complication error.
+     */
+    public AutofixUnsafeCallToThis() {
+        super(null);
+    }
+
+    /**
+     * Method making the unsafe reference on an implicit this.
+     */
+    public void unsafeReferenceOnImplicitThis() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            getClipToPadding();
+        }
+    }
+
+    /**
+     * Method making the unsafe reference on an explicit this.
+     */
+    public void unsafeReferenceOnExplicitThis() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            this.getClipToPadding();
+        }
+    }
+
+    /**
+     * Method making the unsafe reference on an explicit super.
+     */
+    public void unsafeReferenceOnExplicitSuper() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            super.getClipToPadding();
+        }
+    }
+}
diff --git a/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt b/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt
index fe486a3..56316d6 100644
--- a/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt
+++ b/lint-checks/src/main/java/androidx/build/lint/ClassVerificationFailureDetector.kt
@@ -61,8 +61,6 @@
 import org.jetbrains.uast.UThisExpression
 import org.jetbrains.uast.getContainingUClass
 import org.jetbrains.uast.getContainingUMethod
-import org.jetbrains.uast.java.JavaUQualifiedReferenceExpression
-import org.jetbrains.uast.java.JavaUSimpleNameReferenceExpression
 import org.jetbrains.uast.util.isConstructorCall
 import org.jetbrains.uast.util.isMethodCall
 
@@ -522,7 +520,7 @@
                 call.valueArguments,
                 wrapperClassName,
                 wrapperMethodName
-            ) ?: return null
+            )
 
             return fix().name("Extract to static inner class")
                 .composite(
@@ -602,9 +600,7 @@
         }
 
         /**
-         * Generates source code for a call to the generated wrapper method, or `null` if we don't
-         * know how to do that. Currently, this method is capable of handling static calls --
-         * including constructor calls -- and simple reference expressions from Java source code.
+         * Generates source code for a call to the generated wrapper method.
          *
          * Source code follows the general format:
          *
@@ -625,12 +621,7 @@
             callValueArguments: List<UExpression>,
             wrapperClassName: String,
             wrapperMethodName: String,
-        ): String? {
-            var unwrappedCallReceiver = callReceiver
-            while (unwrappedCallReceiver is UParenthesizedExpression) {
-                unwrappedCallReceiver = unwrappedCallReceiver.expression
-            }
-
+        ): String {
             val callReceiverStr = when {
                 // Static method
                 context.evaluator.isStatic(method) ->
@@ -638,17 +629,13 @@
                 // Constructor
                 method.isConstructor ->
                     null
-                // Simple reference
-                unwrappedCallReceiver is JavaUSimpleNameReferenceExpression ->
-                    unwrappedCallReceiver.identifier
-                // Qualified reference
-                unwrappedCallReceiver is JavaUQualifiedReferenceExpression ->
-                    "${unwrappedCallReceiver.receiver}.${unwrappedCallReceiver.selector}"
-                else -> {
-                    // We don't know how to handle this type of receiver. If this happens a lot, we
-                    // might try returning `UElement.asSourceString()` by default.
-                    return null
-                }
+                // If there is no call receiver, and the method isn't a constructor or static,
+                // it must be a call to an instance method using `this` implicitly.
+                callReceiver == null ->
+                    "this"
+                // Otherwise, use the original call receiver string (removing extra parens)
+                else ->
+                    unwrapExpression(callReceiver).asSourceString()
             }
 
             val callValues = if (callValueArguments.isNotEmpty()) {
@@ -665,6 +652,18 @@
         }
 
         /**
+         * Remove parentheses from the expression (unwrap the expression until it is no longer a
+         * UParenthesizedExpression).
+         */
+        private fun unwrapExpression(expr: UExpression): UExpression {
+            var unwrappedExpr = expr
+            while (unwrappedExpr is UParenthesizedExpression) {
+                unwrappedExpr = unwrappedExpr.expression
+            }
+            return unwrappedExpr
+        }
+
+        /**
          * Generates source code for a wrapper method, or `null` if we don't know how to do that.
          * Currently, this method is capable of handling method and constructor calls from Java
          * source code.
diff --git a/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt b/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt
index 04f69a7..aa02f01 100644
--- a/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt
+++ b/lint-checks/src/test/java/androidx/build/lint/ClassVerificationFailureDetectorTest.kt
@@ -446,4 +446,124 @@
 
         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
     }
+
+    @Test
+    fun `Auto-fix for unsafe method call on this`() {
+        val input = arrayOf(
+            javaSample("androidx.AutofixUnsafeCallToThis")
+        )
+
+        /* ktlint-disable max-line-length */
+        val expected = """
+src/androidx/AutofixUnsafeCallToThis.java:39: Error: This call references a method added in API level 21; however, the containing class androidx.AutofixUnsafeCallToThis is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+            getClipToPadding();
+            ~~~~~~~~~~~~~~~~
+src/androidx/AutofixUnsafeCallToThis.java:48: Error: This call references a method added in API level 21; however, the containing class androidx.AutofixUnsafeCallToThis is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+            this.getClipToPadding();
+                 ~~~~~~~~~~~~~~~~
+src/androidx/AutofixUnsafeCallToThis.java:57: Error: This call references a method added in API level 21; however, the containing class androidx.AutofixUnsafeCallToThis is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+            super.getClipToPadding();
+                  ~~~~~~~~~~~~~~~~
+3 errors, 0 warnings
+        """
+
+        val expectedFix = """
+Fix for src/androidx/AutofixUnsafeCallToThis.java line 39: Extract to static inner class:
+@@ -39 +39
+-             getClipToPadding();
++             Api21Impl.getClipToPadding(this);
+@@ -60 +60
++ @annotation.RequiresApi(21)
++ static class Api21Impl {
++     private Api21Impl() {
++         // This class is not instantiable.
++     }
++
++     @annotation.DoNotInline
++     static boolean getClipToPadding(ViewGroup viewGroup) {
++         return viewGroup.getClipToPadding();
++     }
++
+@@ -61 +72
++ }
+Fix for src/androidx/AutofixUnsafeCallToThis.java line 48: Extract to static inner class:
+@@ -48 +48
+-             this.getClipToPadding();
++             Api21Impl.getClipToPadding(this);
+@@ -60 +60
++ @annotation.RequiresApi(21)
++ static class Api21Impl {
++     private Api21Impl() {
++         // This class is not instantiable.
++     }
++
++     @annotation.DoNotInline
++     static boolean getClipToPadding(ViewGroup viewGroup) {
++         return viewGroup.getClipToPadding();
++     }
++
+@@ -61 +72
++ }
+Fix for src/androidx/AutofixUnsafeCallToThis.java line 57: Extract to static inner class:
+@@ -57 +57
+-             super.getClipToPadding();
++             Api21Impl.getClipToPadding(super);
+@@ -60 +60
++ @annotation.RequiresApi(21)
++ static class Api21Impl {
++     private Api21Impl() {
++         // This class is not instantiable.
++     }
++
++     @annotation.DoNotInline
++     static boolean getClipToPadding(ViewGroup viewGroup) {
++         return viewGroup.getClipToPadding();
++     }
++
+@@ -61 +72
++ }
+        """
+        /* ktlint-enable max-line-length */
+
+        check(*input).expect(expected).expectFixDiffs(expectedFix)
+    }
+
+    @Test
+    fun `Auto-fix for unsafe method call on cast object (issue 206111383)`() {
+        val input = arrayOf(
+            javaSample("androidx.AutofixUnsafeCallOnCast")
+        )
+
+        /* ktlint-disable max-line-length */
+        val expected = """
+src/androidx/AutofixUnsafeCallOnCast.java:32: Error: This call references a method added in API level 28; however, the containing class androidx.AutofixUnsafeCallOnCast is reachable from earlier API levels and will fail run-time class verification. [ClassVerificationFailure]
+            ((DisplayCutout) secretDisplayCutout).getSafeInsetTop();
+                                                  ~~~~~~~~~~~~~~~
+1 errors, 0 warnings
+        """
+
+        val expectedFix = """
+Fix for src/androidx/AutofixUnsafeCallOnCast.java line 32: Extract to static inner class:
+@@ -32 +32
+-             ((DisplayCutout) secretDisplayCutout).getSafeInsetTop();
++             Api28Impl.getSafeInsetTop((DisplayCutout) secretDisplayCutout);
+@@ -35 +35
++ @annotation.RequiresApi(28)
++ static class Api28Impl {
++     private Api28Impl() {
++         // This class is not instantiable.
++     }
++
++     @annotation.DoNotInline
++     static int getSafeInsetTop(DisplayCutout displayCutout) {
++         return displayCutout.getSafeInsetTop();
++     }
++
+@@ -36 +47
++ }
+        """
+        /* ktlint-enable max-line-length */
+
+        check(*input).expect(expected).expectFixDiffs(expectedFix)
+    }
 }
diff --git a/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_PermissionTest.java b/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_PermissionTest.java
index 210f503..d3928dc 100644
--- a/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_PermissionTest.java
+++ b/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSession_PermissionTest.java
@@ -45,8 +45,10 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.text.TextUtils;
 
@@ -88,6 +90,7 @@
     @Before
     @Override
     public void setUp() throws Exception {
+        assumeTrue(Build.VERSION.SDK_INT != 17);
         super.setUp();
     }
 
diff --git a/mediarouter/mediarouter/src/main/res/values-te/strings.xml b/mediarouter/mediarouter/src/main/res/values-te/strings.xml
index 5605c42..81f0b97 100644
--- a/mediarouter/mediarouter/src/main/res/values-te/strings.xml
+++ b/mediarouter/mediarouter/src/main/res/values-te/strings.xml
@@ -39,6 +39,6 @@
     <string name="mr_controller_casting_screen" msgid="9171231064758955152">"స్క్రీన్‌ను ప్రసారం చేస్తోంది"</string>
     <string name="mr_dialog_default_group_name" msgid="4115858704575247342">"గ్రూప్"</string>
     <string name="mr_dialog_groupable_header" msgid="4307018456678388936">"పరికరాన్ని జోడించండి"</string>
-    <string name="mr_dialog_transferable_header" msgid="6068257520605505468">"సమూహంలో ప్లే చేయండి"</string>
+    <string name="mr_dialog_transferable_header" msgid="6068257520605505468">"గ్రూప్‌లో ప్లే చేయండి"</string>
     <string name="mr_cast_dialog_title_view_placeholder" msgid="2175930138959078155">"సమాచారం అందుబాటులో లేదు"</string>
 </resources>
diff --git a/navigation/navigation-compose/build.gradle b/navigation/navigation-compose/build.gradle
index 061f2fd..1abfe0c 100644
--- a/navigation/navigation-compose/build.gradle
+++ b/navigation/navigation-compose/build.gradle
@@ -29,7 +29,7 @@
 
     implementation(libs.kotlinStdlib)
     implementation("androidx.compose.foundation:foundation-layout:1.0.1")
-    api("androidx.activity:activity-compose:1.5.0-rc01")
+    api("androidx.activity:activity-compose:1.5.0")
     api("androidx.compose.animation:animation:1.0.1")
     api("androidx.compose.runtime:runtime:1.0.1")
     api("androidx.compose.runtime:runtime-saveable:1.0.1")
diff --git a/navigation/navigation-fragment/build.gradle b/navigation/navigation-fragment/build.gradle
index 29c3a21..9a64a90 100644
--- a/navigation/navigation-fragment/build.gradle
+++ b/navigation/navigation-fragment/build.gradle
@@ -23,7 +23,7 @@
 }
 
 dependencies {
-    api("androidx.fragment:fragment-ktx:1.5.0-rc01")
+    api("androidx.fragment:fragment-ktx:1.5.0")
     api(project(":navigation:navigation-runtime"))
     api("androidx.slidingpanelayout:slidingpanelayout:1.2.0")
     api(libs.kotlinStdlib)
diff --git a/navigation/navigation-runtime/build.gradle b/navigation/navigation-runtime/build.gradle
index dd462d5..6478105 100644
--- a/navigation/navigation-runtime/build.gradle
+++ b/navigation/navigation-runtime/build.gradle
@@ -25,7 +25,7 @@
 
 dependencies {
     api(project(":navigation:navigation-common"))
-    api("androidx.activity:activity-ktx:1.5.0-rc01")
+    api("androidx.activity:activity-ktx:1.5.0")
     api("androidx.lifecycle:lifecycle-runtime-ktx:2.5.0")
     api("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0")
     api("androidx.annotation:annotation-experimental:1.1.0")
diff --git a/navigation/navigation-ui/build.gradle b/navigation/navigation-ui/build.gradle
index 89ba3ad..82b53f9 100644
--- a/navigation/navigation-ui/build.gradle
+++ b/navigation/navigation-ui/build.gradle
@@ -49,6 +49,7 @@
     androidTestImplementation(libs.testExtJunit)
     androidTestImplementation(libs.testCore)
     androidTestImplementation(libs.testRunner)
+    androidTestImplementation(libs.testRules)
     androidTestImplementation(libs.truth)
     androidTestImplementation(libs.multidex)
 }
diff --git a/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/NavigationUITest.kt b/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/NavigationUITest.kt
index 0e0166c..7c4c68e 100644
--- a/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/NavigationUITest.kt
+++ b/navigation/navigation-ui/src/androidTest/java/androidx/navigation/ui/NavigationUITest.kt
@@ -16,13 +16,22 @@
 
 package androidx.navigation.ui
 
+import android.content.Context
+import androidx.appcompat.widget.Toolbar
+import androidx.core.content.res.TypedArrayUtils.getString
 import androidx.navigation.NavGraph
 import androidx.navigation.NavGraphNavigator
+import androidx.navigation.NavHostController
+import androidx.navigation.NavType
+import androidx.navigation.createGraph
 import androidx.navigation.ui.NavigationUI.matchDestinations
+import androidx.test.annotation.UiThreadTest
+import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import androidx.testutils.TestNavigator
 import androidx.testutils.TestNavigatorProvider
+import androidx.testutils.test
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -39,4 +48,33 @@
 
         assertThat(destination.matchDestinations(setOf(1, 2))).isTrue()
     }
+
+    @UiThreadTest
+    @Test
+    fun navigateWithStringReferenceArgs() {
+        val context = ApplicationProvider.getApplicationContext<Context>()
+        val navController = NavHostController(context)
+        navController.navigatorProvider.addNavigator(TestNavigator())
+
+        val startDestination = "start_destination"
+        val endDestination = "end_destination"
+
+        navController.graph = navController.createGraph(startDestination = startDestination) {
+            test(startDestination)
+            test("$endDestination/{test}") {
+                label = "{test}"
+                argument(name = "test") {
+                    type = NavType.ReferenceType
+                }
+            }
+        }
+
+        val toolbar = Toolbar(context).apply { setupWithNavController(navController) }
+        navController.navigate(
+            endDestination + "/${R.string.dest_title}"
+        )
+
+        val expected = context.resources.getString(R.string.dest_title)
+        assertThat(toolbar.title.toString()).isEqualTo(expected)
+    }
 }
diff --git a/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnDestinationChangedListener.kt b/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnDestinationChangedListener.kt
index 948111c3..2c73ae9 100644
--- a/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnDestinationChangedListener.kt
+++ b/navigation/navigation-ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnDestinationChangedListener.kt
@@ -26,6 +26,7 @@
 import androidx.navigation.FloatingWindow
 import androidx.navigation.NavController
 import androidx.navigation.NavDestination
+import androidx.navigation.NavType
 import androidx.navigation.ui.NavigationUI.matchDestinations
 import java.lang.ref.WeakReference
 import java.util.regex.Pattern
@@ -74,7 +75,14 @@
                 val argName = matcher.group(1)
                 if (arguments != null && arguments.containsKey(argName)) {
                     matcher.appendReplacement(title, "")
-                    title.append(arguments[argName].toString())
+
+                    val argType = argName?.let { destination.arguments[argName]?.type }
+                    if (argType == NavType.ReferenceType) {
+                        val value = context.resources.getString(arguments[argName] as Int)
+                        title.append(value)
+                    } else {
+                        title.append(arguments[argName].toString())
+                    }
                 } else {
                     throw IllegalArgumentException(
                         "Could not find \"$argName\" in $arguments to fill label \"$label\""
diff --git a/navigation/navigation-ui/src/main/res/values/strings.xml b/navigation/navigation-ui/src/main/res/values/strings.xml
index 38db102..5f31905 100644
--- a/navigation/navigation-ui/src/main/res/values/strings.xml
+++ b/navigation/navigation-ui/src/main/res/values/strings.xml
@@ -20,4 +20,6 @@
     <string name="nav_app_bar_open_drawer_description">Open navigation drawer</string>
     <!-- Content description for navigating "up" from a Toolbar or action bar. [CHAR LIMIT=NONE] -->
     <string name="nav_app_bar_navigate_up_description">Navigate up</string>
+
+    <string name="dest_title">destination title</string>
 </resources>
diff --git a/playground-common/playground.properties b/playground-common/playground.properties
index 67526e6..a15765d 100644
--- a/playground-common/playground.properties
+++ b/playground-common/playground.properties
@@ -25,7 +25,7 @@
 kotlin.code.style=official
 # Disable docs
 androidx.enableDocumentation=false
-androidx.playground.snapshotBuildId=8716423
+androidx.playground.snapshotBuildId=8736715
 androidx.playground.metalavaBuildId=8670428
 androidx.playground.dokkaBuildId=7472101
 androidx.studio.type=playground
diff --git a/test/uiautomator/integration-tests/testapp/lint-baseline.xml b/test/uiautomator/integration-tests/testapp/lint-baseline.xml
index a4e421a..705e06d 100644
--- a/test/uiautomator/integration-tests/testapp/lint-baseline.xml
+++ b/test/uiautomator/integration-tests/testapp/lint-baseline.xml
@@ -18,622 +18,6 @@
     </issue>
 
     <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testCopy() {"
-        errorLine2="                ~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="85"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzButton() {"
-        errorLine2="                ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="101"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzCheckBox() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="112"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzEditText() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="123"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzProgressBar() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="134"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzRadioButton() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="145"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzRatingBar() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="156"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzSeekBar() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="167"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzSwitch() {"
-        errorLine2="                ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="178"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzTextView() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="189"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzToggleButton() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="200"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzNotFound() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="211"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClazzNull() {"
-        errorLine2="                ~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="221"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testDescSetFromResource() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="258"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testDescSetAtRuntime() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="266"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testDescNotFound() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="274"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testDescNull() {"
-        errorLine2="                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="282"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testPackage() {"
-        errorLine2="                ~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="301"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testPkgNull() {"
-        errorLine2="                ~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="309"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testResUniqueId() {"
-        errorLine2="                ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="324"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testResCommonId() {"
-        errorLine2="                ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="333"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testResNull() {"
-        errorLine2="                ~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="344"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testTextUnique() {"
-        errorLine2="                ~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="370"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testTextCommon() {"
-        errorLine2="                ~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="378"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testTextNull() {"
-        errorLine2="                ~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="387"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testHasUniqueChild() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="402"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testHasCommonChild() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="411"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testGetChildren() {"
-        errorLine2="                ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="420"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testHasMultipleChildren() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="428"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testHasMultipleChildrenCollision() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="439"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testHasChildThatHasChild() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="450"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testHasDescendant() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/BySelectorTests.java"
-            line="460"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testHasBackButton() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTests.java"
-            line="46"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testHasHomeButton() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTests.java"
-            line="52"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testHasRecentsButton() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTests.java"
-            line="58"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testHasStatusBar() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTests.java"
-            line="64"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testGetClassNameButton() throws UiObjectNotFoundException, TimeoutException {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="95"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testGetClassNameCheckBox() throws UiObjectNotFoundException, TimeoutException {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="103"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testGetClassNameEditText() throws UiObjectNotFoundException, TimeoutException {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="111"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testGetClassNameProgressBar() throws UiObjectNotFoundException, TimeoutException {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="119"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testGetClassNameRadioButton() throws UiObjectNotFoundException, TimeoutException {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="127"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testGetClassNameRatingBar() throws UiObjectNotFoundException, TimeoutException {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="135"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testGetClassNameSeekBar() throws UiObjectNotFoundException, TimeoutException {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="143"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testGetClassNameSwitch() throws UiObjectNotFoundException, TimeoutException {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="151"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testGetClassNameTextView() throws UiObjectNotFoundException, TimeoutException {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="159"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testGetClassNameToggleButton() throws UiObjectNotFoundException, TimeoutException {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="167"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClickButton() {"
-        errorLine2="                ~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="205"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClickCheckBox() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="220"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testClickAndWaitForNewWindow() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="234"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testLongClickButton() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="243"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testPinchIn100Percent() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="257"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testPinchIn75Percent() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="268"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testPinchIn50Percent() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="279"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testPinchIn25Percent() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="290"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testScrollDown() {"
-        errorLine2="                ~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="301"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="MissingTestSizeAnnotation"
-        message="Missing test size annotation"
-        errorLine1="    public void testScrollDownToEnd() {"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/androidTest/java/androidx/test/uiautomator/testapp/UiObject2Tests.java"
-            line="346"
-            column="17"/>
-    </issue>
-
-    <issue
         id="UnknownNullness"
         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) {"
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BaseTest.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BaseTest.java
new file mode 100644
index 0000000..0ca27652
--- /dev/null
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/BaseTest.java
@@ -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.test.uiautomator.testapp;
+
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.annotation.NonNull;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.Until;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public abstract class BaseTest {
+
+    private static final long TIMEOUT_MS = 10_000;
+    protected static final String TEST_APP = "androidx.test.uiautomator.testapp";
+
+    protected UiDevice mDevice;
+
+    @Before
+    public void setUp() {
+        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+    }
+
+    @After
+    public void tearDown() {
+        mDevice.pressHome();
+        assertTrue("Test app still visible after teardown",
+                mDevice.wait(Until.gone(By.pkg(TEST_APP)), TIMEOUT_MS));
+    }
+
+    protected void launchTestActivity(@NonNull Class<? extends Activity> activity) {
+        Context context = ApplicationProvider.getApplicationContext();
+        context.startActivity(new Intent().setClass(context, activity)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
+        assertTrue("Test app not visible after launching activity",
+                mDevice.wait(Until.hasObject(By.pkg(TEST_APP)), TIMEOUT_MS));
+    }
+}
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 d8c1cd8..ae677dd 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
@@ -16,8 +16,11 @@
 
 package androidx.test.uiautomator.testapp;
 
-import android.content.Context;
-import android.content.Intent;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
 import android.widget.Button;
 import android.widget.CheckBox;
 import android.widget.EditText;
@@ -29,253 +32,216 @@
 import android.widget.TextView;
 import android.widget.ToggleButton;
 
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.BySelector;
-import androidx.test.uiautomator.UiDevice;
 import androidx.test.uiautomator.UiObject2;
-import androidx.test.uiautomator.Until;
 
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.regex.Pattern;
 
-@RunWith(AndroidJUnit4.class)
-public class BySelectorTests {
-
-    private static final String TAG = BySelectorTests.class.getSimpleName();
-
-    private static final String TEST_APP = "androidx.test.uiautomator.testapp";
-    private static final String ANDROID_WIDGET_PACKAGE = "android.widget";
-
-    private UiDevice mDevice;
-
-    @Before
-    public void setUp() throws Exception {
-        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-    }
-
-    public void launchTestActivity(String activity) {
-        // Launch the test app
-        Context context = ApplicationProvider.getApplicationContext();
-        Intent intent = new Intent()
-                .setClassName(TEST_APP, String.format("%s.%s", TEST_APP, activity))
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        context.startActivity(intent);
-
-        // Wait for activity to appear
-        mDevice.wait(Until.hasObject(By.pkg(TEST_APP)), 10000);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        mDevice.pressHome();
-
-        // Wait for the activity to disappear
-        mDevice.wait(Until.gone(By.pkg(TEST_APP)), 5000);
-    }
+public class BySelectorTests extends BaseTest {
 
     @Test
     public void testCopy() {
-        launchTestActivity("MainActivity");
+        launchTestActivity(MainActivity.class);
 
         // Base selector
         BySelector base = By.clazz(".TextView");
 
         // Select various TextView instances
-        Assert.assertNotNull(mDevice.findObject(By.copy(base).text("Text View 1")));
-        Assert.assertNotNull(mDevice.findObject(By.copy(base).text("Item1")));
-        Assert.assertNotNull(mDevice.findObject(By.copy(base).text("Item3")));
+        assertNotNull(mDevice.findObject(By.copy(base).text("Text View 1")));
+        assertNotNull(mDevice.findObject(By.copy(base).text("Item1")));
+        assertNotNull(mDevice.findObject(By.copy(base).text("Item3")));
 
         // Shouldn't be able to select an object that does not match the base
-        Assert.assertNull(mDevice.findObject(By.copy(base).text("Accessible button")));
+        assertNull(mDevice.findObject(By.copy(base).text("Accessible button")));
     }
 
     @Test
     public void testClazzButton() {
-        launchTestActivity("BySelectorTestClazzActivity");
+        launchTestActivity(BySelectorTestClazzActivity.class);
 
         // Button
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget", "Button")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget.Button")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(".Button")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(Button.class)));
+        assertNotNull(mDevice.findObject(By.clazz("android.widget", "Button")));
+        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");
+        launchTestActivity(BySelectorTestClazzActivity.class);
 
         // CheckBox
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget", "CheckBox")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget.CheckBox")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(".CheckBox")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(CheckBox.class)));
+        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");
+        launchTestActivity(BySelectorTestClazzActivity.class);
 
         // EditText
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget", "EditText")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget.EditText")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(".EditText")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(EditText.class)));
+        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");
+        launchTestActivity(BySelectorTestClazzActivity.class);
 
         // ProgressBar
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget", "ProgressBar")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget.ProgressBar")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(".ProgressBar")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(ProgressBar.class)));
+        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");
+        launchTestActivity(BySelectorTestClazzActivity.class);
 
         // RadioButton
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget", "RadioButton")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget.RadioButton")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(".RadioButton")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(RadioButton.class)));
+        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");
+        launchTestActivity(BySelectorTestClazzActivity.class);
 
         // RatingBar
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget", "RatingBar")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget.RatingBar")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(".RatingBar")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(RatingBar.class)));
+        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");
+        launchTestActivity(BySelectorTestClazzActivity.class);
 
         // SeekBar
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget", "SeekBar")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget.SeekBar")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(".SeekBar")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(SeekBar.class)));
+        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");
+        launchTestActivity(BySelectorTestClazzActivity.class);
 
         // Switch
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget", "Switch")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget.Switch")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(".Switch")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(Switch.class)));
+        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");
+        launchTestActivity(BySelectorTestClazzActivity.class);
 
         // TextView
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget", "TextView")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget.TextView")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(".TextView")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(TextView.class)));
+        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");
+        launchTestActivity(BySelectorTestClazzActivity.class);
 
         // ToggleButton
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget", "ToggleButton")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz("android.widget.ToggleButton")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(".ToggleButton")));
-        Assert.assertNotNull(mDevice.findObject(By.clazz(ToggleButton.class)));
+        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");
+        launchTestActivity(BySelectorTestClazzActivity.class);
 
-        // Non-existant class
-        Assert.assertNull(mDevice.findObject(By.clazz("android.widget", "NonExistantClass")));
-        Assert.assertNull(mDevice.findObject(By.clazz("android.widget.NonExistantClass")));
-        Assert.assertNull(mDevice.findObject(By.clazz(".NonExistantClass")));
+        // Non-existent class
+        assertNull(mDevice.findObject(By.clazz("android.widget", "NonExistentClass")));
+        assertNull(mDevice.findObject(By.clazz("android.widget.NonExistentClass")));
+        assertNull(mDevice.findObject(By.clazz(".NonExistentClass")));
     }
 
     @Test
     public void testClazzNull() {
         // clazz(String)
         try {
-            mDevice.findObject(By.clazz((String)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.clazz((String) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
 
         // clazz(String, String)
         try {
-            mDevice.findObject(By.clazz((String)null, "foo"));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.clazz((String) null, "foo"));
+            fail();
+        } catch (NullPointerException expected) {
+        }
 
         try {
-            mDevice.findObject(By.clazz("foo", (String)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.clazz("foo", (String) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
 
         // clazz(Class)
         try {
-            mDevice.findObject(By.clazz((Class)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.clazz((Class) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
 
         // clazz(Pattern)
         try {
-            mDevice.findObject(By.clazz((Pattern)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.clazz((Pattern) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
     }
 
-    // TODO(allenhair): Implement these for clazz():
+    // TODO(b/235841286): Implement these for clazz():
     // 1. Custom class
     // 2. Patterns
     // 3. Runtime Widgets
 
     @Test
     public void testDescSetFromResource() {
-        launchTestActivity("BySelectorTestDescActivity");
+        launchTestActivity(BySelectorTestDescActivity.class);
 
         // Content Description from resource
-        Assert.assertNotNull(mDevice.findObject(By.desc("Content Description Set From Layout")));
+        assertNotNull(mDevice.findObject(By.desc("Content Description Set From Layout")));
     }
 
     @Test
     public void testDescSetAtRuntime() {
-        launchTestActivity("BySelectorTestDescActivity");
+        launchTestActivity(BySelectorTestDescActivity.class);
 
         // Content Description set at runtime
-        Assert.assertNotNull(mDevice.findObject(By.desc("Content Description Set At Runtime")));
+        assertNotNull(mDevice.findObject(By.desc("Content Description Set At Runtime")));
     }
 
     @Test
     public void testDescNotFound() {
-        launchTestActivity("BySelectorTestDescActivity");
+        launchTestActivity(BySelectorTestDescActivity.class);
 
         // No element has this content description
-        Assert.assertNull(mDevice.findObject(By.desc("No element has this Content Description")));
+        assertNull(mDevice.findObject(By.desc("No element has this Content Description")));
     }
 
     @Test
@@ -283,59 +249,63 @@
         // desc(String)
         try {
             mDevice.findObject(By.desc((String) null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            fail();
+        } catch (NullPointerException expected) {
+        }
 
         // desc(Pattern)
         try {
-            mDevice.findObject(By.desc((Pattern)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.desc((Pattern) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
     }
 
-    // TODO(allenhair): Implement these for desc():
+    // TODO(b/235841286): Implement these for desc():
     // 1. Patterns
     // 2. Runtime Widgets
 
     @Test
     public void testPackage() {
-        launchTestActivity("MainActivity");
+        launchTestActivity(MainActivity.class);
 
         // Full match with string argument
-        Assert.assertNotNull(mDevice.findObject(By.pkg(TEST_APP)));
+        assertNotNull(mDevice.findObject(By.pkg(TEST_APP)));
     }
 
     @Test
     public void testPkgNull() {
         // pkg(String)
         try {
-            mDevice.findObject(By.pkg((String)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.pkg((String) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
 
         // pkg(Pattern)
         try {
-            mDevice.findObject(By.pkg((Pattern)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.pkg((Pattern) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
     }
 
     @Test
     public void testResUniqueId() {
-        launchTestActivity("BySelectorTestResActivity");
+        launchTestActivity(BySelectorTestResActivity.class);
 
         // Unique ID
-        Assert.assertNotNull(mDevice.findObject(By.res(TEST_APP, "unique_id")));
-        Assert.assertNotNull(mDevice.findObject(By.res(TEST_APP + ":id/unique_id")));
+        assertNotNull(mDevice.findObject(By.res(TEST_APP, "unique_id")));
+        assertNotNull(mDevice.findObject(By.res(TEST_APP + ":id/unique_id")));
     }
 
     @Test
     public void testResCommonId() {
-        launchTestActivity("BySelectorTestResActivity");
+        launchTestActivity(BySelectorTestResActivity.class);
 
         // Shared ID
-        Assert.assertNotNull(mDevice.findObject(By.res(TEST_APP, "shared_id")));
-        Assert.assertNotNull(mDevice.findObject(By.res(TEST_APP + ":id/shared_id")));
+        assertNotNull(mDevice.findObject(By.res(TEST_APP, "shared_id")));
+        assertNotNull(mDevice.findObject(By.res(TEST_APP + ":id/shared_id")));
         // 1. Make sure we can see all instances
         // 2. Differentiate between matches by other criteria
     }
@@ -344,126 +314,133 @@
     public void testResNull() {
         // res(String)
         try {
-            mDevice.findObject(By.res((String)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.res((String) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
 
         // res(String, String)
         try {
-            mDevice.findObject(By.res((String)null, "foo"));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.res((String) null, "foo"));
+            fail();
+        } catch (NullPointerException expected) {
+        }
 
         try {
-            mDevice.findObject(By.res("foo", (String)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.res("foo", (String) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
 
         // res(Pattern)
         try {
-            mDevice.findObject(By.res((Pattern)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.res((Pattern) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
     }
 
     @Test
     public void testTextUnique() {
-        launchTestActivity("BySelectorTestTextActivity");
+        launchTestActivity(BySelectorTestTextActivity.class);
 
         // Unique Text
-        Assert.assertNotNull(mDevice.findObject(By.text("Unique Text")));
+        assertNotNull(mDevice.findObject(By.text("Unique Text")));
     }
 
     @Test
     public void testTextCommon() {
-        launchTestActivity("BySelectorTestTextActivity");
+        launchTestActivity(BySelectorTestTextActivity.class);
 
         // Common Text
-        Assert.assertNotNull(mDevice.findObject(By.text("Common Text")));
-        Assert.assertEquals(2, mDevice.findObjects(By.text("Common Text")).size());
+        assertNotNull(mDevice.findObject(By.text("Common Text")));
+        assertEquals(2, mDevice.findObjects(By.text("Common Text")).size());
     }
 
     @Test
     public void testTextNull() {
         // text(String)
         try {
-            mDevice.findObject(By.text((String)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.text((String) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
 
         // text(Pattern)
         try {
-            mDevice.findObject(By.text((Pattern)null));
-            Assert.fail();
-        } catch (NullPointerException e) {}
+            mDevice.findObject(By.text((Pattern) null));
+            fail();
+        } catch (NullPointerException expected) {
+        }
     }
 
     @Test
     public void testHasUniqueChild() {
-        launchTestActivity("BySelectorTestHasChildActivity");
+        launchTestActivity(BySelectorTestHasChildActivity.class);
 
         // Find parent with unique child
         UiObject2 object = mDevice.findObject(By.hasChild(By.res(TEST_APP, "toplevel1_child1")));
-        Assert.assertNotNull(object);
+        assertNotNull(object);
     }
 
     @Test
     public void testHasCommonChild() {
-        launchTestActivity("BySelectorTestHasChildActivity");
+        launchTestActivity(BySelectorTestHasChildActivity.class);
 
         // Find parent(s) with common child
-        Assert.assertNotNull(mDevice.findObject(By.pkg(TEST_APP).hasChild(By.clazz(".TextView"))));
-        Assert.assertEquals(3, mDevice.findObjects(By.pkg(TEST_APP).hasChild(By.clazz(".TextView"))).size());
+        assertNotNull(mDevice.findObject(By.pkg(TEST_APP).hasChild(By.clazz(".TextView"))));
+        assertEquals(3,
+                mDevice.findObjects(By.pkg(TEST_APP).hasChild(By.clazz(".TextView"))).size());
     }
 
     @Test
     public void testGetChildren() {
-        launchTestActivity("BySelectorTestHasChildActivity");
+        launchTestActivity(BySelectorTestHasChildActivity.class);
 
         UiObject2 parent = mDevice.findObject(By.res(TEST_APP, "toplevel2"));
-        Assert.assertEquals(2, parent.getChildren().size());
+        assertEquals(2, parent.getChildren().size());
     }
 
     @Test
     public void testHasMultipleChildren() {
-        launchTestActivity("BySelectorTestHasChildActivity");
+        launchTestActivity(BySelectorTestHasChildActivity.class);
 
         // Select parent with multiple hasChild selectors
         UiObject2 object = mDevice.findObject(By
                 .hasChild(By.res(TEST_APP, "toplevel2_child1"))
                 .hasChild(By.res(TEST_APP, "toplevel2_child2")));
-        Assert.assertNotNull(object);
+        assertNotNull(object);
     }
 
     @Test
     public void testHasMultipleChildrenCollision() {
-        launchTestActivity("BySelectorTestHasChildActivity");
+        launchTestActivity(BySelectorTestHasChildActivity.class);
 
         // Select parent with multiple hasChild selectors, but single child that matches both
         UiObject2 object = mDevice.findObject(By
                 .hasChild(By.res(TEST_APP, "toplevel1_child1"))
                 .hasChild(By.clazz(".TextView")));
-        Assert.assertNotNull(object);
+        assertNotNull(object);
     }
 
     @Test
     public void testHasChildThatHasChild() {
-        launchTestActivity("BySelectorTestHasChildActivity");
+        launchTestActivity(BySelectorTestHasChildActivity.class);
 
         // Select parent with child that has a child
         UiObject2 object = mDevice.findObject(
                 By.hasChild(By.hasChild(By.res(TEST_APP, "toplevel3_container1_child1"))));
-        Assert.assertNotNull(object);
+        assertNotNull(object);
     }
 
     @Test
     public void testHasDescendant() {
-        launchTestActivity("BySelectorTestHasChildActivity");
+        launchTestActivity(BySelectorTestHasChildActivity.class);
 
         // Select a LinearLayout that has a unique descendant
         UiObject2 object = mDevice.findObject(By
                 .clazz(".RelativeLayout")
                 .hasDescendant(By.res(TEST_APP, "toplevel3_container1_child1")));
-        Assert.assertNotNull(object);
+        assertNotNull(object);
     }
 }
diff --git a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTests.java b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTests.java
index d7630be..2fac576 100644
--- a/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTests.java
+++ b/test/uiautomator/integration-tests/testapp/src/androidTest/java/androidx/test/uiautomator/testapp/MultiWindowTests.java
@@ -16,56 +16,40 @@
 
 package androidx.test.uiautomator.testapp;
 
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SdkSuppress;
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
+import static org.junit.Assert.assertTrue;
 
-import org.junit.Assert;
-import org.junit.Before;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.uiautomator.By;
+
 import org.junit.Ignore;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
-@RunWith(AndroidJUnit4.class)
-public class MultiWindowTests {
-
-    private UiDevice mDevice;
-    private static final String TEST_APP = "androidx.test.uiautomator.testapp";
-
-    @Before
-    public void setUp() {
-        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-
-        mDevice.pressHome();
-        mDevice.waitForIdle();
-    }
+public class MultiWindowTests extends BaseTest {
 
     @Test
     @Ignore
-    @SdkSuppress(minSdkVersion=21)
+    @SdkSuppress(minSdkVersion = 21)
     public void testHasBackButton() {
-        Assert.assertTrue(mDevice.hasObject(By.res("com.android.systemui", "back")));
+        assertTrue(mDevice.hasObject(By.res("com.android.systemui", "back")));
     }
 
     @Test
     @Ignore
-    @SdkSuppress(minSdkVersion=21)
+    @SdkSuppress(minSdkVersion = 21)
     public void testHasHomeButton() {
-        Assert.assertTrue(mDevice.hasObject(By.res("com.android.systemui", "home")));
+        assertTrue(mDevice.hasObject(By.res("com.android.systemui", "home")));
     }
 
     @Test
     @Ignore
-    @SdkSuppress(minSdkVersion=21)
+    @SdkSuppress(minSdkVersion = 21)
     public void testHasRecentsButton() {
-        Assert.assertTrue(mDevice.hasObject(By.res("com.android.systemui", "recent_apps")));
+        assertTrue(mDevice.hasObject(By.res("com.android.systemui", "recent_apps")));
     }
 
     @Test
-    @SdkSuppress(minSdkVersion=21)
+    @SdkSuppress(minSdkVersion = 21)
     public void testHasStatusBar() {
-        Assert.assertTrue(mDevice.hasObject(By.res("com.android.systemui", "status_bar")));
+        assertTrue(mDevice.hasObject(By.res("com.android.systemui", "status_bar")));
     }
-}
\ No newline at end of file
+}
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 596df2c..375c0147 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
@@ -16,163 +16,150 @@
 
 package androidx.test.uiautomator.testapp;
 
-import android.content.Context;
-import android.content.Intent;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.graphics.Rect;
 import android.os.SystemClock;
 
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.FlakyTest;
-import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.Direction;
-import androidx.test.uiautomator.UiDevice;
 import androidx.test.uiautomator.UiObject2;
-import androidx.test.uiautomator.UiObjectNotFoundException;
 import androidx.test.uiautomator.Until;
 
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
-import java.util.concurrent.TimeoutException;
-
-@RunWith(AndroidJUnit4.class)
-public class UiObject2Tests {
-
-    private static final String TEST_APP = "androidx.test.uiautomator.testapp";
-
-    private UiDevice mDevice;
-
-    @Before
-    public void setUp() throws Exception {
-        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        mDevice.pressHome();
-    }
-
-    private class LaunchActivityRunnable implements Runnable {
-
-        private String mActivity;
-
-        public LaunchActivityRunnable(String activity) {
-            mActivity = activity;
-        }
-
-        @Override
-        public void run() {
-            Context context = ApplicationProvider.getApplicationContext();
-            Intent intent = new Intent()
-                    .setClassName(TEST_APP, String.format("%s.%s", TEST_APP, mActivity))
-                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            context.startActivity(intent);
-        }
-    }
-
-    private void launchTestActivity(String activity) {
-        // Launch the test app
-        mDevice.performActionAndWait(new LaunchActivityRunnable(activity), Until.newWindow(), 5000);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        mDevice.pressHome();
-
-        // Wait for the activity to disappear
-        mDevice.wait(Until.gone(By.pkg(TEST_APP)), 5000);
-    }
-
-    /* TODO(allenhair): Implement these tests
-    public void testExists() {}
-
-    public void testGetChildCount() {}
-
-    public void testGetVisibleBounds() {}
-    */
+public class UiObject2Tests extends BaseTest {
 
     @Test
-    public void testGetClassNameButton() throws UiObjectNotFoundException, TimeoutException {
-        launchTestActivity("UiObject2TestGetClassNameActivity");
+    public void testHasObject() {
+        launchTestActivity(MainActivity.class);
+
+        UiObject2 object = mDevice.findObject(By.pkg(TEST_APP));
+
+        assertTrue(object.hasObject(By.text("Text View 1")));
+        assertFalse(object.hasObject(By.text("")));
+    }
+
+    @Test
+    public void testGetChildCount() {
+        launchTestActivity(MainActivity.class);
+
+        UiObject2 object = mDevice.findObject(By.res(TEST_APP, "example_id"));
+        assertEquals(0, object.getChildCount());
+
+        UiObject2 nestedObject = mDevice.findObject(By.res(TEST_APP, "nested_elements"));
+        assertEquals(2, nestedObject.getChildCount());
+    }
+
+    @Test
+    public void testGetVisibleBounds() {
+        launchTestActivity(MainActivity.class);
+
+        UiObject2 object = mDevice.findObject(By.pkg(TEST_APP));
+        Rect bounds = object.getVisibleBounds();
+        int top = bounds.top;
+        int bottom = bounds.bottom;
+        int left = bounds.left;
+        int right = bounds.right;
+        int boundsHeight = bounds.height();
+        int boundsWidth = bounds.width();
+        int displayHeight = mDevice.getDisplayHeight();
+        int displayWidth = mDevice.getDisplayWidth();
+        // Test the lower bounds
+        assertTrue(0 <= top);
+        assertTrue(0 <= left);
+        assertTrue(top < bottom);
+        assertTrue(left < right);
+        // Test the upper bounds
+        assertTrue(boundsHeight < displayHeight);
+        assertTrue(boundsWidth < displayWidth);
+    }
+
+    @Test
+    public void testGetClassNameButton() {
+        launchTestActivity(UiObject2TestGetClassNameActivity.class);
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "button"));
-        Assert.assertEquals("android.widget.Button", object.getClassName());
+        assertEquals("android.widget.Button", object.getClassName());
     }
 
     @Test
-    public void testGetClassNameCheckBox() throws UiObjectNotFoundException, TimeoutException {
-        launchTestActivity("UiObject2TestGetClassNameActivity");
+    public void testGetClassNameCheckBox() {
+        launchTestActivity(UiObject2TestGetClassNameActivity.class);
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "check_box"));
-        Assert.assertEquals("android.widget.CheckBox", object.getClassName());
+        assertEquals("android.widget.CheckBox", object.getClassName());
     }
 
     @Test
-    public void testGetClassNameEditText() throws UiObjectNotFoundException, TimeoutException {
-        launchTestActivity("UiObject2TestGetClassNameActivity");
+    public void testGetClassNameEditText() {
+        launchTestActivity(UiObject2TestGetClassNameActivity.class);
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "edit_text"));
-        Assert.assertEquals("android.widget.EditText", object.getClassName());
+        assertEquals("android.widget.EditText", object.getClassName());
     }
 
     @Test
-    public void testGetClassNameProgressBar() throws UiObjectNotFoundException, TimeoutException {
-        launchTestActivity("UiObject2TestGetClassNameActivity");
+    public void testGetClassNameProgressBar() {
+        launchTestActivity(UiObject2TestGetClassNameActivity.class);
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "progress_bar"));
-        Assert.assertEquals("android.widget.ProgressBar", object.getClassName());
+        assertEquals("android.widget.ProgressBar", object.getClassName());
     }
 
     @Test
-    public void testGetClassNameRadioButton() throws UiObjectNotFoundException, TimeoutException {
-        launchTestActivity("UiObject2TestGetClassNameActivity");
+    public void testGetClassNameRadioButton() {
+        launchTestActivity(UiObject2TestGetClassNameActivity.class);
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "radio_button"));
-        Assert.assertEquals("android.widget.RadioButton", object.getClassName());
+        assertEquals("android.widget.RadioButton", object.getClassName());
     }
 
     @Test
-    public void testGetClassNameRatingBar() throws UiObjectNotFoundException, TimeoutException {
-        launchTestActivity("UiObject2TestGetClassNameActivity");
+    public void testGetClassNameRatingBar() {
+        launchTestActivity(UiObject2TestGetClassNameActivity.class);
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "rating_bar"));
-        Assert.assertEquals("android.widget.RatingBar", object.getClassName());
+        assertEquals("android.widget.RatingBar", object.getClassName());
     }
 
     @Test
-    public void testGetClassNameSeekBar() throws UiObjectNotFoundException, TimeoutException {
-        launchTestActivity("UiObject2TestGetClassNameActivity");
+    public void testGetClassNameSeekBar() {
+        launchTestActivity(UiObject2TestGetClassNameActivity.class);
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "seek_bar"));
-        Assert.assertEquals("android.widget.SeekBar", object.getClassName());
+        assertEquals("android.widget.SeekBar", object.getClassName());
     }
 
     @Test
-    public void testGetClassNameSwitch() throws UiObjectNotFoundException, TimeoutException {
-        launchTestActivity("UiObject2TestGetClassNameActivity");
+    public void testGetClassNameSwitch() {
+        launchTestActivity(UiObject2TestGetClassNameActivity.class);
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "switch_toggle"));
-        Assert.assertEquals("android.widget.Switch", object.getClassName());
+        assertEquals("android.widget.Switch", object.getClassName());
     }
 
     @Test
-    public void testGetClassNameTextView() throws UiObjectNotFoundException, TimeoutException {
-        launchTestActivity("UiObject2TestGetClassNameActivity");
+    public void testGetClassNameTextView() {
+        launchTestActivity(UiObject2TestGetClassNameActivity.class);
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "text_view"));
-        Assert.assertEquals("android.widget.TextView", object.getClassName());
+        assertEquals("android.widget.TextView", object.getClassName());
     }
 
     @Test
-    public void testGetClassNameToggleButton() throws UiObjectNotFoundException, TimeoutException {
-        launchTestActivity("UiObject2TestGetClassNameActivity");
+    public void testGetClassNameToggleButton() {
+        launchTestActivity(UiObject2TestGetClassNameActivity.class);
 
         UiObject2 object = mDevice.findObject(By.res(TEST_APP, "toggle_button"));
-        Assert.assertEquals("android.widget.ToggleButton", object.getClassName());
+        assertEquals("android.widget.ToggleButton", object.getClassName());
     }
 
-    /* TODO(allenhair): Implement more tests
+    /* TODO(b/235841473): Implement more tests
     public void testGetContentDescription() {}
 
     public void testGetApplicationPackage() {}
@@ -204,36 +191,36 @@
 
     @Test
     public void testClickButton() {
-        launchTestActivity("UiObject2TestClickActivity");
+        launchTestActivity(UiObject2TestClickActivity.class);
 
         // Find the button and verify its initial state
         UiObject2 button = mDevice.findObject(By.res(TEST_APP, "button"));
-        Assert.assertEquals("Click Me!", button.getText());
+        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);
-        Assert.assertEquals("I've been clicked!", button.getText());
+        assertEquals("I've been clicked!", button.getText());
     }
 
     @Test
     public void testClickCheckBox() {
-        launchTestActivity("UiObject2TestClickActivity");
+        launchTestActivity(UiObject2TestClickActivity.class);
 
         // Find the checkbox and verify its initial state
         UiObject2 checkbox = mDevice.findObject(By.res(TEST_APP, "check_box"));
-        Assert.assertEquals(false, checkbox.isChecked());
+        assertFalse(checkbox.isChecked());
 
         // Click on the checkbox and verify that it is now checked
         checkbox.click();
         checkbox.wait(Until.checked(true), 10000);
-        Assert.assertEquals(true, checkbox.isChecked());
+        assertTrue(checkbox.isChecked());
     }
 
     @Test
     public void testClickAndWaitForNewWindow() {
-        launchTestActivity("UiObject2TestClickAndWaitActivity");
+        launchTestActivity(UiObject2TestClickAndWaitActivity.class);
 
         // Click the button and wait for a new window
         UiObject2 button = mDevice.findObject(By.res(TEST_APP, "new_window_button"));
@@ -242,21 +229,21 @@
 
     @Test
     public void testLongClickButton() {
-        launchTestActivity("UiObject2TestLongClickActivity");
+        launchTestActivity(UiObject2TestLongClickActivity.class);
 
         // Find the button and verify its initial state
         UiObject2 button = mDevice.findObject(By.res(TEST_APP, "button"));
-        Assert.assertEquals("Long Click Me!", button.getText());
+        assertEquals("Long Click Me!", button.getText());
 
         // Click on the button and verify that the text has changed
         button.longClick();
         button.wait(Until.textEquals("I've been long clicked!"), 10000);
-        Assert.assertEquals("I've been long clicked!", button.getText());
+        assertEquals("I've been long clicked!", button.getText());
     }
 
     @Test
     public void testPinchIn100Percent() {
-        launchTestActivity("UiObject2TestPinchActivity");
+        launchTestActivity(UiObject2TestPinchActivity.class);
 
         // Find the area to pinch
         UiObject2 pinchArea = mDevice.findObject(By.res(TEST_APP, "pinch_area"));
@@ -267,7 +254,7 @@
 
     @Test
     public void testPinchIn75Percent() {
-        launchTestActivity("UiObject2TestPinchActivity");
+        launchTestActivity(UiObject2TestPinchActivity.class);
 
         // Find the area to pinch
         UiObject2 pinchArea = mDevice.findObject(By.res(TEST_APP, "pinch_area"));
@@ -278,7 +265,7 @@
 
     @Test
     public void testPinchIn50Percent() {
-        launchTestActivity("UiObject2TestPinchActivity");
+        launchTestActivity(UiObject2TestPinchActivity.class);
 
         // Find the area to pinch
         UiObject2 pinchArea = mDevice.findObject(By.res(TEST_APP, "pinch_area"));
@@ -289,7 +276,7 @@
 
     @Test
     public void testPinchIn25Percent() {
-        launchTestActivity("UiObject2TestPinchActivity");
+        launchTestActivity(UiObject2TestPinchActivity.class);
 
         // Find the area to pinch
         UiObject2 pinchArea = mDevice.findObject(By.res(TEST_APP, "pinch_area"));
@@ -301,27 +288,26 @@
     @Test
     @FlakyTest
     public void testScrollDown() {
-        launchTestActivity("UiObject2TestVerticalScrollActivity");
+        launchTestActivity(UiObject2TestVerticalScrollActivity.class);
 
         // Make sure we're at the top
-        Assert.assertNotNull(mDevice.findObject(By.res(TEST_APP, "top_text")));
+        assertNotNull(mDevice.findObject(By.res(TEST_APP, "top_text")));
 
         UiObject2 scrollView = mDevice.findObject(By.res(TEST_APP, "scroll_view"));
         Rect bounds = scrollView.getVisibleBounds();
-        float distance = 50000 / (bounds.height() - 2*10);
+        float distance = 50000 / (bounds.height() - 2 * 10);
 
-        //
         //scrollView.scroll(Direction.DOWN, 1.0f);
         //assertNull(mDevice.findObject(By.res(TEST_APP, "top_text")));
         //while (scrollView.scroll(Direction.DOWN, 1.0f)) {
         //}
         scrollView.scroll(Direction.DOWN, distance);
-        Assert.assertNotNull(mDevice.findObject(By.res(TEST_APP, "bottom_text")));
+        assertNotNull(mDevice.findObject(By.res(TEST_APP, "bottom_text")));
     }
 
-    /* TODO(allenhair): Fix this test
+    /* TODO(b/235841473): Fix this test
     public void testScrollDistance() {
-        launchTestActivity("UiObject2TestVerticalScrollActivity");
+        launchTestActivity(UiObject2TestVerticalScrollActivity.class);
 
         // Make sure we're at the top
         assertNotNull(mDevice.findObject(By.res(TEST_APP, "top_text")));
@@ -347,21 +333,23 @@
     @Test
     @FlakyTest
     public void testScrollDownToEnd() {
-        launchTestActivity("UiObject2TestVerticalScrollActivity");
+        launchTestActivity(UiObject2TestVerticalScrollActivity.class);
 
         // Make sure we're at the top
-        Assert.assertNotNull(mDevice.findObject(By.res(TEST_APP, "top_text")));
+        assertNotNull(mDevice.findObject(By.res(TEST_APP, "top_text")));
 
         // Scroll as much as we can
         UiObject2 scrollView = mDevice.findObject(By.res(TEST_APP, "scroll_view"));
         scrollView.wait(Until.scrollable(true), 5000);
-        while (scrollView.scroll(Direction.DOWN, 1.0f)) { }
+        while (scrollView.scroll(Direction.DOWN, 1.0f)) {
+            // Continue until bottom.
+        }
 
         // Make sure we're at the bottom
-        Assert.assertNotNull(mDevice.findObject(By.res(TEST_APP, "bottom_text")));
+        assertNotNull(mDevice.findObject(By.res(TEST_APP, "bottom_text")));
     }
 
-    /* TODO(allenhair): Implement these tests
+    /* TODO(b/235841473): Implement these tests
     public void testSetText() {}
 
     public void testWaitForExists() {}
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 3d26529..a7d4ab1 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
@@ -26,6 +26,9 @@
 import androidx.tracing.perfetto.Tracing.EnableTracingResponse
 import androidx.tracing.perfetto.TracingReceiver.Companion.ACTION_ENABLE_TRACING
 import java.io.File
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.ThreadPoolExecutor
+import java.util.concurrent.TimeUnit
 
 /** Allows for enabling tracing in an app using a broadcast. @see [ACTION_ENABLE_TRACING] */
 @RestrictTo(LIBRARY)
@@ -77,6 +80,16 @@
     )
     internal annotation class EnableTracingResultCode
 
+    private val executor by lazy {
+        ThreadPoolExecutor(
+            /* corePoolSize = */ 0,
+            /* maximumPoolSize = */ 1,
+            /* keepAliveTime = */ 10, // gives time for tooling to side-load the .so file
+            /* unit = */ TimeUnit.SECONDS,
+            /* workQueue = */ LinkedBlockingQueue()
+        )
+    }
+
     // TODO: check value on app start
     override fun onReceive(context: Context?, intent: Intent?) {
         if (intent == null || intent.action != ACTION_ENABLE_TRACING) return
@@ -85,7 +98,20 @@
         // will be used if present.
         val srcPath = intent.extras?.getString(KEY_PATH)
 
-        val response: EnableTracingResponse = when {
+        val pendingResult = goAsync()
+
+        executor.execute {
+            try {
+                val response = enableTracing(srcPath, context)
+                pendingResult.setResult(response.exitCode, response.toJsonString(), null)
+            } finally {
+                pendingResult.finish()
+            }
+        }
+    }
+
+    private fun enableTracing(srcPath: String?, context: Context?): EnableTracingResponse =
+        when {
             Build.VERSION.SDK_INT < Build.VERSION_CODES.R -> {
                 // TODO(234351579): Support API < 30
                 EnableTracingResponse(
@@ -118,9 +144,6 @@
             }
         }
 
-        setResult(response.exitCode, response.toJsonString(), null)
-    }
-
     private fun copyExternalLibraryFile(
         context: Context,
         srcPath: String
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/AndroidManifest.xml b/wear/compose/compose-material/src/androidAndroidTest/AndroidManifest.xml
similarity index 91%
rename from wear/compose/compose-material/src/androidAndroidTest/kotlin/AndroidManifest.xml
rename to wear/compose/compose-material/src/androidAndroidTest/AndroidManifest.xml
index bcb362e..f405734 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/AndroidManifest.xml
+++ b/wear/compose/compose-material/src/androidAndroidTest/AndroidManifest.xml
@@ -15,4 +15,4 @@
   limitations under the License.
   -->
 
-<manifest package="androidx.wear.compose.material" />
+<manifest package="androidx.wear.compose.material.test" />
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ButtonScreenshotTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ButtonScreenshotTest.kt
index 1dfe638..37b49c2 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ButtonScreenshotTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ButtonScreenshotTest.kt
@@ -22,7 +22,6 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.testTag
-import androidx.compose.ui.test.ExperimentalTestApi
 import androidx.compose.ui.test.captureToImage
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
@@ -39,7 +38,6 @@
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-@OptIn(ExperimentalTestApi::class)
 class ButtonScreenshotTest {
 
     @get:Rule
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/CardScreenshotTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/CardScreenshotTest.kt
new file mode 100644
index 0000000..6edabec
--- /dev/null
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/CardScreenshotTest.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.wear.compose.material.test
+
+import android.os.Build
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import androidx.wear.compose.material.AppCard
+import androidx.wear.compose.material.CardDefaults
+import androidx.wear.compose.material.SCREENSHOT_GOLDEN_PATH
+import androidx.wear.compose.material.TEST_TAG
+import androidx.wear.compose.material.TestIcon
+import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.TitleCard
+import androidx.wear.compose.material.setContentWithTheme
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class CardScreenshotTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+    @get:Rule
+    val testName = TestName()
+
+    @Test
+    fun app_card_ltr() = verifyScreenshot(layoutDirection = LayoutDirection.Ltr) {
+        sampleAppCard()
+    }
+
+    @Test
+    fun app_card_disabled() = verifyScreenshot(layoutDirection = LayoutDirection.Ltr) {
+        sampleAppCard(enabled = false)
+    }
+
+    @Test
+    fun app_card_rtl() = verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+        sampleAppCard()
+    }
+
+    @Test
+    fun title_card_ltr() = verifyScreenshot(layoutDirection = LayoutDirection.Ltr) {
+        sampleTitleCard()
+    }
+
+    @Test
+    fun title_card_disabled() = verifyScreenshot(layoutDirection = LayoutDirection.Ltr) {
+        sampleTitleCard(enabled = false)
+    }
+
+    @Test
+    fun title_card_rtl() = verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+        sampleTitleCard()
+    }
+
+    @Test
+    fun title_card_image_background() = verifyScreenshot {
+        sampleTitleCard(
+            backgroundPainter = CardDefaults.imageWithScrimBackgroundPainter(
+                backgroundImagePainter = painterResource(id = R.drawable.backgroundimage1))
+        )
+    }
+
+    @Composable
+    private fun sampleAppCard(enabled: Boolean = true) {
+        AppCard(
+            enabled = enabled,
+            onClick = {},
+            appName = { Text("AppName") },
+            appImage = { TestIcon() },
+            title = { Text("AppCard") },
+            time = { Text("now") },
+            modifier = Modifier.testTag(TEST_TAG),
+        ) {
+            Text("Some body content")
+            Text("and some more body content")
+        }
+    }
+
+    @Composable
+    private fun sampleTitleCard(
+        enabled: Boolean = true,
+        backgroundPainter: Painter = CardDefaults.cardBackgroundPainter()
+    ) {
+        TitleCard(
+            enabled = enabled,
+            onClick = {},
+            title = { Text("TitleCard") },
+            time = { Text("now") },
+            backgroundPainter = backgroundPainter,
+            modifier = Modifier.testTag(TEST_TAG),
+        ) {
+            Text("Some body content")
+            Text("and some more body content")
+        }
+    }
+
+    private fun verifyScreenshot(
+        layoutDirection: LayoutDirection = LayoutDirection.Ltr,
+        content: @Composable () -> Unit
+    ) {
+        rule.setContentWithTheme {
+            CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
+                content()
+            }
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, testName.methodName)
+    }
+}
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ChipScreenshotTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ChipScreenshotTest.kt
new file mode 100644
index 0000000..a8731b4
--- /dev/null
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ChipScreenshotTest.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.wear.compose.material.test
+
+import android.os.Build
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import androidx.wear.compose.material.Chip
+import androidx.wear.compose.material.ChipColors
+import androidx.wear.compose.material.ChipDefaults
+import androidx.wear.compose.material.CompactChip
+import androidx.wear.compose.material.SCREENSHOT_GOLDEN_PATH
+import androidx.wear.compose.material.TEST_TAG
+import androidx.wear.compose.material.TestIcon
+import androidx.wear.compose.material.Text
+import androidx.wear.compose.material.setContentWithTheme
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class ChipScreenshotTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+    @get:Rule
+    val testName = TestName()
+
+    @Test
+    fun chip_ltr() = verifyScreenshot(layoutDirection = LayoutDirection.Ltr) {
+        sampleChip()
+    }
+
+    @Test
+    fun chip_rtl() = verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+        sampleChip()
+    }
+
+    @Test
+    fun chip_disabled() = verifyScreenshot(layoutDirection = LayoutDirection.Ltr) {
+        sampleChip(enabled = false)
+    }
+
+    @Test
+    fun chip_gradient_ltr() = verifyScreenshot(layoutDirection = LayoutDirection.Ltr) {
+        sampleChip(colors = ChipDefaults.gradientBackgroundChipColors())
+    }
+
+    @Test
+    fun chip_gradient_rtl() = verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+        sampleChip(colors = ChipDefaults.gradientBackgroundChipColors())
+    }
+
+    @Test
+    fun chip_image_background() = verifyScreenshot {
+        sampleChip(colors = ChipDefaults.imageBackgroundChipColors(
+            backgroundImagePainter = painterResource(id = R.drawable.backgroundimage1)))
+    }
+
+    @Test
+    fun compact_chip_ltr() = verifyScreenshot(layoutDirection = LayoutDirection.Ltr) {
+        sampleCompactChip()
+    }
+
+    @Test
+    fun compact_chip_rtl() = verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+        sampleCompactChip()
+    }
+
+    @Test
+    fun compact_chip_disabled() = verifyScreenshot(layoutDirection = LayoutDirection.Ltr) {
+        sampleCompactChip(enabled = false)
+    }
+
+    @Composable
+    private fun sampleChip(
+        enabled: Boolean = true,
+        colors: ChipColors = ChipDefaults.primaryChipColors()
+    ) {
+        Chip(
+            enabled = enabled,
+            colors = colors,
+            onClick = {},
+            label = { Text("Standard chip") },
+            secondaryLabel = { Text("Secondary text") },
+            icon = { TestIcon() },
+            modifier = Modifier.testTag(TEST_TAG),
+        )
+    }
+
+    @Composable
+    private fun sampleCompactChip(enabled: Boolean = true) {
+        CompactChip(
+            enabled = enabled,
+            onClick = {},
+            label = { Text("Compact chip") },
+            icon = { TestIcon() },
+            modifier = Modifier.testTag(TEST_TAG),
+        )
+    }
+
+    private fun verifyScreenshot(
+        layoutDirection: LayoutDirection = LayoutDirection.Ltr,
+        content: @Composable () -> Unit
+    ) {
+        rule.setContentWithTheme {
+            CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
+                content()
+            }
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, testName.methodName)
+    }
+}
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PickerScreenshotTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PickerScreenshotTest.kt
new file mode 100644
index 0000000..6b00164
--- /dev/null
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/PickerScreenshotTest.kt
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.wear.compose.material
+
+import android.os.Build
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.Row
+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.offset
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class PickerScreenshotTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+    @get:Rule
+    val testName = TestName()
+
+    private val screenHeight = 150.dp
+
+    @Test
+    fun picker() = verifyScreenshot {
+        samplePicker()
+    }
+
+    @Test
+    fun picker_without_gradient() = verifyScreenshot {
+        samplePicker(gradientRatio = 0f)
+    }
+
+    @Test
+    fun picker_negative_separation() = verifyScreenshot {
+        samplePicker(separation = -8.dp)
+    }
+
+    @Test
+    fun dual_picker() = verifyScreenshot {
+        dualPicker()
+    }
+
+    @Test
+    fun dual_picker_with_readonlylabel() = verifyScreenshot {
+        dualPicker(readOnlyLabel = "Min")
+    }
+
+    @Composable
+    private fun samplePicker(
+        gradientRatio: Float = PickerDefaults.DefaultGradientRatio,
+        separation: Dp = 0.dp,
+    ) {
+        Box(
+            modifier = Modifier
+                .height(screenHeight).fillMaxWidth().background(MaterialTheme.colors.background),
+            contentAlignment = Alignment.Center
+        ) {
+            val items = listOf("One", "Two", "Three", "Four", "Five")
+            val state = rememberPickerState(items.size)
+            Picker(
+                modifier = Modifier.fillMaxSize().testTag(TEST_TAG),
+                state = state,
+                gradientRatio = gradientRatio,
+                separation = separation,
+                contentDescription = { "" },
+            ) {
+                Text(items[it])
+            }
+        }
+    }
+
+    @Composable
+    private fun dualPicker(readOnlyLabel: String? = null) {
+        // This test verifies read-only mode alongside an 'editable' Picker.
+        val textStyle = MaterialTheme.typography.display1
+
+        @Composable
+        fun Option(color: Color, text: String) = Box(modifier = Modifier.fillMaxSize()) {
+            Text(
+                text = text, style = textStyle, color = color,
+                modifier = Modifier
+                    .align(Alignment.Center)
+                    .wrapContentSize()
+            )
+        }
+
+        Row(
+            modifier = Modifier
+                .height(screenHeight)
+                .fillMaxWidth()
+                .background(MaterialTheme.colors.background)
+                .testTag(TEST_TAG),
+            verticalAlignment = Alignment.CenterVertically,
+            horizontalArrangement = Arrangement.Center,
+        ) {
+            Picker(
+                state = rememberPickerState(
+                    initialNumberOfOptions = 100,
+                    initiallySelectedOption = 11
+                ),
+                contentDescription = { "" },
+                readOnly = false,
+                modifier = Modifier.size(64.dp, 100.dp),
+                option = { Option(MaterialTheme.colors.secondary, "%2d".format(it)) }
+            )
+            Spacer(Modifier.width(8.dp))
+            Text(text = ":", style = textStyle, color = MaterialTheme.colors.onBackground)
+            Spacer(Modifier.width(8.dp))
+            Picker(
+                state = rememberPickerState(
+                    initialNumberOfOptions = 100,
+                    initiallySelectedOption = 100
+                ),
+                contentDescription = { "" },
+                readOnly = true,
+                readOnlyLabel = { if (readOnlyLabel != null) LabelText(readOnlyLabel) },
+                modifier = Modifier.size(64.dp, 100.dp),
+                option = { Option(MaterialTheme.colors.onBackground, "%02d".format(it)) }
+            )
+        }
+    }
+
+    @Composable
+    private fun BoxScope.LabelText(text: String) {
+        Text(
+            text = text,
+            style = MaterialTheme.typography.caption1,
+            color = MaterialTheme.colors.onSurfaceVariant,
+            modifier = Modifier.align(Alignment.TopCenter).offset(y = 8.dp)
+        )
+    }
+
+    private fun verifyScreenshot(
+        layoutDirection: LayoutDirection = LayoutDirection.Ltr,
+        content: @Composable () -> Unit
+    ) {
+        rule.setContentWithTheme {
+            CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
+                content()
+            }
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, testName.methodName)
+    }
+}
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ToggleButtonScreenshotTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ToggleButtonScreenshotTest.kt
index abbb11b..59a6702 100644
--- a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ToggleButtonScreenshotTest.kt
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ToggleButtonScreenshotTest.kt
@@ -22,7 +22,6 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.testTag
-import androidx.compose.ui.test.ExperimentalTestApi
 import androidx.compose.ui.test.captureToImage
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
@@ -39,7 +38,6 @@
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-@OptIn(ExperimentalTestApi::class)
 class ToggleButtonScreenshotTest {
 
     @get:Rule
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ToggleChipScreenshotTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ToggleChipScreenshotTest.kt
new file mode 100644
index 0000000..d01d31dc
--- /dev/null
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/ToggleChipScreenshotTest.kt
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.wear.compose.material
+
+import android.os.Build
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class ToggleChipScreenshotTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+    @get:Rule
+    val testName = TestName()
+
+    @Test
+    fun toggle_chip_checkbox() = verifyScreenshot {
+        sampleToggleChip(checked = true)
+    }
+
+    @Test
+    fun toggle_chip_checkbox_unchecked() = verifyScreenshot {
+        sampleToggleChip(checked = false)
+    }
+
+    @Test
+    fun toggle_chip_checkbox_rtl() = verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+        sampleToggleChip()
+    }
+
+    @Test
+    fun toggle_chip_radio() = verifyScreenshot {
+        val checked = true
+        sampleToggleChip(
+            toggleControl = {
+                Icon(
+                    imageVector = ToggleChipDefaults.radioIcon(checked),
+                    contentDescription = ""
+                )
+            },
+            checked = checked
+        )
+    }
+
+    @Test
+    fun toggle_chip_radio_unchecked() = verifyScreenshot {
+        val checked = false
+        sampleToggleChip(
+            toggleControl = {
+                Icon(
+                    imageVector = ToggleChipDefaults.radioIcon(checked),
+                    contentDescription = ""
+                )
+            },
+            checked = checked,
+        )
+    }
+
+    @Test
+    fun toggle_chip_switch_checked() = verifyScreenshot {
+        val checked = true
+        sampleToggleChip(
+            toggleControl = {
+                Icon(
+                    imageVector = ToggleChipDefaults.switchIcon(checked),
+                    contentDescription = ""
+                )
+            },
+            checked = checked,
+        )
+    }
+
+    @Test
+    fun toggle_chip_switch_unchecked() = verifyScreenshot {
+        val checked = false
+        sampleToggleChip(
+            colors = ToggleChipDefaults.toggleChipColors(
+                uncheckedToggleControlColor = ToggleChipDefaults.SwitchUncheckedIconColor
+            ),
+            toggleControl = {
+                // For Switch  toggle controls the Wear Material UX guidance is to set the
+                // unselected toggle control color to ToggleChipDefaults.switchUncheckedIconColor()
+                // rather than the default.
+                Icon(
+                    imageVector = ToggleChipDefaults.switchIcon(checked),
+                    contentDescription = ""
+                )
+            },
+            checked = checked,
+        )
+    }
+
+    @Test
+    fun toggle_chip_disabled() = verifyScreenshot {
+        sampleToggleChip(
+            enabled = false,
+        )
+    }
+
+    @Test
+    fun split_toggle_chip() = verifyScreenshot {
+        sampleSplitToggleChip()
+    }
+
+    @Test
+    fun split_toggle_chip_rtl() = verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+        sampleSplitToggleChip()
+    }
+
+    @Test
+    fun split_toggle_chip_disabled() = verifyScreenshot {
+        sampleSplitToggleChip(enabled = false)
+    }
+
+    @Composable
+    private fun sampleToggleChip(
+        colors: ToggleChipColors = ToggleChipDefaults.toggleChipColors(),
+        enabled: Boolean = true,
+        checked: Boolean = true,
+        toggleControl: @Composable () -> Unit = {
+            Icon(
+                imageVector = ToggleChipDefaults.checkboxIcon(checked = checked),
+                contentDescription = ""
+            )
+        },
+    ) {
+        ToggleChip(
+            appIcon = { TestIcon() },
+            label = {
+                Text("Standard toggle chip", maxLines = 1, overflow = TextOverflow.Ellipsis)
+            },
+            secondaryLabel = {
+                Text("Secondary label", maxLines = 1, overflow = TextOverflow.Ellipsis)
+            },
+            checked = checked,
+            enabled = enabled,
+            colors = colors,
+            toggleControl = toggleControl,
+            onCheckedChange = {},
+            modifier = Modifier.testTag(TEST_TAG),
+        )
+    }
+
+    @Composable
+    private fun sampleSplitToggleChip(
+        enabled: Boolean = true,
+    ) {
+        SplitToggleChip(
+            label = {
+                Text("Split chip", maxLines = 1, overflow = TextOverflow.Ellipsis)
+            },
+            secondaryLabel = {
+                Text("Secondary", maxLines = 1, overflow = TextOverflow.Ellipsis)
+            },
+            checked = true,
+            enabled = enabled,
+            toggleControl = {
+                Icon(
+                    imageVector = ToggleChipDefaults.checkboxIcon(checked = true),
+                    contentDescription = ""
+                )
+            },
+            onCheckedChange = {},
+            onClick = {},
+            modifier = Modifier.testTag(TEST_TAG),
+        )
+    }
+
+    private fun verifyScreenshot(
+        layoutDirection: LayoutDirection = LayoutDirection.Ltr,
+        content: @Composable () -> Unit
+    ) {
+        rule.setContentWithTheme {
+            CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
+                content()
+            }
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, testName.methodName)
+    }
+}
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/VignetteScreenshotTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/VignetteScreenshotTest.kt
new file mode 100644
index 0000000..0f1a3a9
--- /dev/null
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/VignetteScreenshotTest.kt
@@ -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.wear.compose.material
+
+import android.os.Build
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class VignetteScreenshotTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+    @get:Rule
+    val testName = TestName()
+
+    private val screenSize = 340.dp
+
+    @Test
+    fun vignette_circular_top() = verifyScreenshot {
+        ConfiguredShapeScreen(isRound = true) {
+            sampleVignette(
+                VignettePosition.Top,
+                modifier = Modifier.size(screenSize).clip(CircleShape)
+            )
+        }
+    }
+
+    @Test
+    fun vignette_circular_bottom() = verifyScreenshot {
+        ConfiguredShapeScreen(isRound = true) {
+            sampleVignette(
+                VignettePosition.Bottom,
+                modifier = Modifier.size(screenSize).clip(CircleShape)
+            )
+        }
+    }
+
+    @Test
+    fun vignette_circular_top_and_bottom() = verifyScreenshot {
+        ConfiguredShapeScreen(isRound = true) {
+            sampleVignette(
+                VignettePosition.TopAndBottom,
+                modifier = Modifier.size(screenSize).clip(CircleShape)
+            )
+        }
+    }
+
+    @Test
+    fun vignette_square_top() = verifyScreenshot {
+        sampleVignette(VignettePosition.Top)
+    }
+
+    @Test
+    fun vignette_square_bottom() = verifyScreenshot {
+        sampleVignette(VignettePosition.Bottom)
+    }
+
+    @Test
+    fun vignette_square_top_and_bottom() = verifyScreenshot {
+        sampleVignette(VignettePosition.TopAndBottom)
+    }
+
+    @Composable
+    fun sampleVignette(
+        vignettePosition: VignettePosition,
+        modifier: Modifier = Modifier.size(screenSize)
+    ) {
+        Scaffold(
+            vignette = { Vignette(vignettePosition = vignettePosition) },
+            modifier = Modifier.testTag(TEST_TAG)
+        ) {
+            Box(
+                modifier = modifier,
+                contentAlignment = Alignment.Center
+            ) {
+            }
+        }
+    }
+
+    private fun verifyScreenshot(
+        content: @Composable () -> Unit
+    ) {
+        rule.setContentWithTheme {
+            content()
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, testName.methodName)
+    }
+}
diff --git a/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/dialog/DialogScreenshotTest.kt b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/dialog/DialogScreenshotTest.kt
new file mode 100644
index 0000000..3fe3e49
--- /dev/null
+++ b/wear/compose/compose-material/src/androidAndroidTest/kotlin/androidx/wear/compose/material/dialog/DialogScreenshotTest.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.wear.compose.material
+
+import android.os.Build
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import androidx.wear.compose.material.dialog.Alert
+import androidx.wear.compose.material.dialog.Confirmation
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class DialogScreenshotTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+    @get:Rule
+    val testName = TestName()
+
+    @Test
+    fun alert_title_body_and_buttons() = verifyScreenshot {
+        Alert(
+            title = {
+                Text(
+                    text = "Power off",
+                    textAlign = TextAlign.Center,
+                    color = MaterialTheme.colors.onBackground
+                )
+            },
+            negativeButton = {
+                Button(
+                    onClick = {},
+                    colors = ButtonDefaults.secondaryButtonColors()
+                ) {
+                    Text("No")
+                }
+            },
+            positiveButton = {
+                Button(
+                    onClick = {},
+                    colors = ButtonDefaults.primaryButtonColors()
+                ) {
+                    Text("Yes")
+                }
+            },
+            modifier = Modifier.testTag(TEST_TAG),
+        ) {
+            Text(
+                text = "Are you sure?",
+                textAlign = TextAlign.Center,
+                style = MaterialTheme.typography.body2,
+                color = MaterialTheme.colors.onBackground,
+            )
+        }
+    }
+
+    @Test
+    fun alert_icon_title_and_buttons() = verifyScreenshot {
+        Alert(
+            icon = { TestIcon() },
+            title = {
+                Text(
+                    text = "Allow access to location?",
+                    textAlign = TextAlign.Center,
+                    color = MaterialTheme.colors.onBackground
+                )
+            },
+            negativeButton = {
+                Button(
+                    onClick = {},
+                    colors = ButtonDefaults.secondaryButtonColors()
+                ) {
+                    Text("No")
+                }
+            },
+            positiveButton = {
+                Button(
+                    onClick = {},
+                    colors = ButtonDefaults.primaryButtonColors()
+                ) {
+                    Text("Yes")
+                }
+            },
+            modifier = Modifier.testTag(TEST_TAG),
+        )
+    }
+
+    @Test
+    fun alert_icon_title_and_chip() = verifyScreenshot {
+        Alert(
+            icon = { TestIcon() },
+            title = { Text(
+                text = "Grant location permission to use this app",
+                textAlign = TextAlign.Center
+            ) },
+            modifier = Modifier.testTag(TEST_TAG),
+        ) {
+            item {
+                Chip(
+                    icon = { TestIcon() },
+                    label = { Text("Settings") },
+                    onClick = {},
+                    colors = ChipDefaults.secondaryChipColors(),
+                )
+            }
+        }
+    }
+
+    @Test
+    fun alert_title_message_and_chip() = verifyScreenshot {
+        Alert(
+            verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.Top),
+            title = {
+                Row(modifier = Modifier.fillMaxWidth(),
+                    horizontalArrangement = Arrangement.Center) {
+                    Text(text = "Title that is quite long", textAlign = TextAlign.Center)
+                }
+            },
+            message = {
+                Text(
+                    text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+                    textAlign = TextAlign.Center,
+                    style = MaterialTheme.typography.body2
+                )
+            },
+            modifier = Modifier.testTag(TEST_TAG),
+        ) {
+            item {
+                Chip(
+                    icon = { TestIcon() },
+                    label = { Text("Allow access") },
+                    onClick = {},
+                    colors = ChipDefaults.primaryChipColors(),
+                )
+            }
+        }
+    }
+
+    @Test
+    fun confirmation() = verifyScreenshot {
+        Confirmation(
+            onTimeout = {},
+            icon = { TestIcon() },
+            modifier = Modifier.testTag(TEST_TAG),
+        ) {
+            Text(
+                text = "Success",
+                textAlign = TextAlign.Center
+            )
+        }
+    }
+
+    private fun verifyScreenshot(
+        content: @Composable () -> Unit
+    ) {
+        rule.setContentWithTheme {
+             content()
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertAgainstGolden(screenshotRule, testName.methodName)
+    }
+}
diff --git a/wear/compose/compose-material/src/androidAndroidTest/res/drawable/backgroundimage1.png b/wear/compose/compose-material/src/androidAndroidTest/res/drawable/backgroundimage1.png
new file mode 100644
index 0000000..fbb9332
--- /dev/null
+++ b/wear/compose/compose-material/src/androidAndroidTest/res/drawable/backgroundimage1.png
Binary files differ
diff --git a/wear/watchface/watchface-client-guava/src/androidTest/java/androidx/wear/watchface/client/guava/ListenableWatchFaceMetadataClientTest.kt b/wear/watchface/watchface-client-guava/src/androidTest/java/androidx/wear/watchface/client/guava/ListenableWatchFaceMetadataClientTest.kt
index 98ce3be..05be0f5 100644
--- a/wear/watchface/watchface-client-guava/src/androidTest/java/androidx/wear/watchface/client/guava/ListenableWatchFaceMetadataClientTest.kt
+++ b/wear/watchface/watchface-client-guava/src/androidTest/java/androidx/wear/watchface/client/guava/ListenableWatchFaceMetadataClientTest.kt
@@ -46,7 +46,7 @@
     private val realService = object : WatchFaceControlService() {
         @SuppressLint("NewApi")
         override fun createServiceStub(): IWatchFaceInstanceServiceStub =
-            IWatchFaceInstanceServiceStub(this, MainScope())
+            IWatchFaceInstanceServiceStub(this@WatchFaceControlTestService, MainScope())
 
         init {
             setContext(ApplicationProvider.getApplicationContext<Context>())
diff --git a/wear/watchface/watchface-complications-data/build.gradle b/wear/watchface/watchface-complications-data/build.gradle
index 874613c..838601e 100644
--- a/wear/watchface/watchface-complications-data/build.gradle
+++ b/wear/watchface/watchface-complications-data/build.gradle
@@ -33,8 +33,7 @@
     implementation("androidx.core:core:1.1.0")
     implementation("androidx.preference:preference:1.1.0")
     implementation("androidx.annotation:annotation:1.2.0")
-    implementation("androidx.wear.tiles:tiles:1.0.0")
-    implementation("androidx.wear.tiles:tiles-proto:1.0.0")
+    implementation("androidx.wear.tiles:tiles:1.1.0-alpha08")
     testImplementation(libs.testCore)
     testImplementation(libs.testRunner)
     testImplementation(libs.testRules)
diff --git a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
index ef61db0..2644dfb 100644
--- a/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
+++ b/wear/watchface/watchface-complications-data/src/main/java/androidx/wear/watchface/complications/data/Data.kt
@@ -21,8 +21,6 @@
 import android.graphics.drawable.Icon
 import android.os.Build
 import androidx.annotation.RestrictTo
-import androidx.wear.tiles.proto.LayoutElementProto
-import androidx.wear.tiles.proto.ResourceProto
 import androidx.wear.tiles.LayoutElementBuilders
 import androidx.wear.tiles.ResourceBuilders
 import java.time.Instant
@@ -1530,23 +1528,17 @@
 
     /** The [LayoutElementBuilders.Layout] to be displayed when the device is ambient. */
     public val ambientLayout: LayoutElementBuilders.Layout by lazy {
-        LayoutElementBuilders.Layout.fromProto(
-            LayoutElementProto.Layout.parseFrom(ambientLayoutWireFormat)
-        )
+        LayoutElementBuilders.Layout.fromByteArray(ambientLayoutWireFormat)!!
     }
 
     /** The [LayoutElementBuilders.Layout] to be displayed when the device is interactive. */
     public val interactiveLayout: LayoutElementBuilders.Layout by lazy {
-        LayoutElementBuilders.Layout.fromProto(
-             LayoutElementProto.Layout.parseFrom(interactiveLayoutWireFormat)
-        )
+        LayoutElementBuilders.Layout.fromByteArray(interactiveLayoutWireFormat)!!
     }
 
     /** The [ResourceBuilders.Resources] for [ambientLayout] and [interactiveLayout]. */
     public val layoutResources: ResourceBuilders.Resources by lazy {
-        ResourceBuilders.Resources.fromProto(
-            ResourceProto.Resources.parseFrom(layoutResourcesWireFormat)
-        )
+        ResourceBuilders.Resources.fromByteArray(layoutResourcesWireFormat)!!
     }
 
     /**
@@ -1584,9 +1576,9 @@
             resources: ResourceBuilders.Resources,
             contentDescription: ComplicationText
         ) : this(
-            ambientLayout.toProto().toByteArray(),
-            interactiveLayout.toProto().toByteArray(),
-            resources.toProto().toByteArray(),
+            ambientLayout.toByteArray(),
+            interactiveLayout.toByteArray(),
+            resources.toByteArray(),
             contentDescription
         )
 
diff --git a/wear/watchface/watchface-complications/src/main/java/androidx/wear/watchface/complications/ComplicationSlotBounds.kt b/wear/watchface/watchface-complications/src/main/java/androidx/wear/watchface/complications/ComplicationSlotBounds.kt
index c3b78e0..9b6ea15 100644
--- a/wear/watchface/watchface-complications/src/main/java/androidx/wear/watchface/complications/ComplicationSlotBounds.kt
+++ b/wear/watchface/watchface-complications/src/main/java/androidx/wear/watchface/complications/ComplicationSlotBounds.kt
@@ -80,7 +80,7 @@
 
         other as ComplicationSlotBounds
 
-        if (perComplicationTypeBounds == other.perComplicationTypeBounds) return false
+        if (perComplicationTypeBounds != other.perComplicationTypeBounds) return false
         return perComplicationTypeMargins == other.perComplicationTypeMargins
     }
 
diff --git a/wear/watchface/watchface-data/api/restricted_current.txt b/wear/watchface/watchface-data/api/restricted_current.txt
index 5c31ca1..1686d18 100644
--- a/wear/watchface/watchface-data/api/restricted_current.txt
+++ b/wear/watchface/watchface-data/api/restricted_current.txt
@@ -270,8 +270,7 @@
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @androidx.versionedparcelable.VersionedParcelize public class ComplicationOverlayWireFormat implements android.os.Parcelable androidx.versionedparcelable.VersionedParcelable {
-    ctor public ComplicationOverlayWireFormat(int, Boolean?, java.util.Map<java.lang.Integer!,android.graphics.RectF!>?, Integer?, java.util.Map<java.lang.Integer!,android.graphics.RectF!>?);
-    ctor @Deprecated public ComplicationOverlayWireFormat(int, Boolean?, java.util.Map<java.lang.Integer!,android.graphics.RectF!>?, Integer?);
+    ctor public ComplicationOverlayWireFormat(int, Boolean?, java.util.Map<java.lang.Integer!,android.graphics.RectF!>?, Integer?);
     method public int describeContents();
     method public Integer? getAccessibilityTraversalIndex();
     method public void writeToParcel(android.os.Parcel, int);
@@ -283,12 +282,13 @@
     field @androidx.versionedparcelable.ParcelField(1) public int mComplicationSlotId;
     field @androidx.versionedparcelable.ParcelField(2) public int mEnabled;
     field @androidx.versionedparcelable.ParcelField(3) public java.util.Map<java.lang.Integer!,android.graphics.RectF!>? mPerComplicationTypeBounds;
-    field @androidx.versionedparcelable.ParcelField(5) public java.util.Map<java.lang.Integer!,android.graphics.RectF!>? mPerComplicationTypeMargins;
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @androidx.versionedparcelable.VersionedParcelize public class ComplicationsOptionWireFormat extends androidx.wear.watchface.style.data.OptionWireFormat {
-    ctor public ComplicationsOptionWireFormat(byte[], CharSequence, android.graphics.drawable.Icon?, androidx.wear.watchface.style.data.ComplicationOverlayWireFormat![]);
+    ctor public ComplicationsOptionWireFormat(byte[], CharSequence, android.graphics.drawable.Icon?, androidx.wear.watchface.style.data.ComplicationOverlayWireFormat![], java.util.List<androidx.wear.watchface.style.data.PerComplicationTypeMargins!>?);
+    ctor @Deprecated public ComplicationsOptionWireFormat(byte[], CharSequence, android.graphics.drawable.Icon?, androidx.wear.watchface.style.data.ComplicationOverlayWireFormat![]);
     field @androidx.versionedparcelable.ParcelField(100) public androidx.wear.watchface.style.data.ComplicationOverlayWireFormat![] mComplicationOverlays;
+    field @androidx.versionedparcelable.ParcelField(value=101, defaultValue="null") public java.util.List<androidx.wear.watchface.style.data.PerComplicationTypeMargins!>? mComplicationOverlaysMargins;
     field @androidx.versionedparcelable.ParcelField(2) public CharSequence mDisplayName;
     field @androidx.versionedparcelable.ParcelField(3) public android.graphics.drawable.Icon? mIcon;
   }
@@ -344,6 +344,11 @@
     field @androidx.versionedparcelable.ParcelField(1) public byte[] mId;
   }
 
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @androidx.versionedparcelable.VersionedParcelize public class PerComplicationTypeMargins implements androidx.versionedparcelable.VersionedParcelable {
+    ctor public PerComplicationTypeMargins(java.util.Map<java.lang.Integer!,android.graphics.RectF!>);
+    field @androidx.versionedparcelable.ParcelField(1) public java.util.Map<java.lang.Integer!,android.graphics.RectF!> mPerComplicationTypeMargins;
+  }
+
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @androidx.versionedparcelable.VersionedParcelize public class UserStyleFlavorWireFormat implements android.os.Parcelable androidx.versionedparcelable.VersionedParcelable {
     ctor public UserStyleFlavorWireFormat(String, androidx.wear.watchface.style.data.UserStyleWireFormat, java.util.Map<java.lang.Integer!,androidx.wear.watchface.complications.data.DefaultComplicationDataSourcePolicyWireFormat!>);
     method public int describeContents();
diff --git a/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/data/ComplicationSlotMetadataWireFormat.java b/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/data/ComplicationSlotMetadataWireFormat.java
index 5be361e..8180132 100644
--- a/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/data/ComplicationSlotMetadataWireFormat.java
+++ b/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/data/ComplicationSlotMetadataWireFormat.java
@@ -96,10 +96,10 @@
     @Nullable
     BoundingArcWireFormat mBoundingArc;
 
-    @ParcelField(15)
-    @Nullable
     // This needs to be a list because VersionedParcelable appears not to be backwards compatible
     // when introducing new arrays.
+    @ParcelField(value = 15, defaultValue = "null")
+    @Nullable
     List<RectF> mComplicationMargins;
 
     /** Used by VersionedParcelable. */
diff --git a/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/data/ComplicationStateWireFormat.java b/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/data/ComplicationStateWireFormat.java
index b8d5348..759bacf 100644
--- a/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/data/ComplicationStateWireFormat.java
+++ b/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/data/ComplicationStateWireFormat.java
@@ -107,7 +107,7 @@
     @Nullable
     BoundingArcWireFormat mBoundingArc;
 
-    @ParcelField(17)
+    @ParcelField(value = 17, defaultValue = "null")
     @Nullable
     Rect mBoundsWithMargins;
 
diff --git a/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/style/data/ComplicationOverlayWireFormat.java b/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/style/data/ComplicationOverlayWireFormat.java
index 060b550..e72de56 100644
--- a/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/style/data/ComplicationOverlayWireFormat.java
+++ b/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/style/data/ComplicationOverlayWireFormat.java
@@ -59,9 +59,8 @@
     @ParcelField(4)
     long mAccessibilityTraversalIndex;
 
-    @ParcelField(5)
-    @Nullable
-    public Map<Integer, RectF> mPerComplicationTypeMargins;
+    // IMPORTANT: DO NOT EXTEND THIS FILE! IT WILL NOT BE BACKWARDS COMPATIBLE :(
+    // Instead extend ComplicationsOptionWireFormat.
 
     ComplicationOverlayWireFormat() {
     }
@@ -70,8 +69,7 @@
             int complicationSlotId,
             @Nullable Boolean enabled,
             @Nullable Map<Integer, RectF> perComplicationTypeBounds,
-            @Nullable Integer accessibilityTraversalIndex,
-            @Nullable Map<Integer, RectF> perComplicationTypeMargins
+            @Nullable Integer accessibilityTraversalIndex
     ) {
         mComplicationSlotId = complicationSlotId;
         if (enabled != null) {
@@ -85,19 +83,6 @@
         } else {
             mAccessibilityTraversalIndex = accessibilityTraversalIndex;
         }
-        mPerComplicationTypeMargins = perComplicationTypeMargins;
-    }
-
-    /** @deprecated Use a constructor with perComplicationTypeMargins instead. */
-    @Deprecated
-    public ComplicationOverlayWireFormat(
-            int complicationSlotId,
-            @Nullable Boolean enabled,
-            @Nullable Map<Integer, RectF> perComplicationTypeBounds,
-            @Nullable Integer accessibilityTraversalIndex
-    ) {
-        this(complicationSlotId, enabled, perComplicationTypeBounds, accessibilityTraversalIndex,
-                null);
     }
 
     @Override
diff --git a/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/style/data/ComplicationsOptionWireFormat.java b/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/style/data/ComplicationsOptionWireFormat.java
index acbc93a..e15e08a 100644
--- a/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/style/data/ComplicationsOptionWireFormat.java
+++ b/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/style/data/ComplicationsOptionWireFormat.java
@@ -24,6 +24,8 @@
 import androidx.versionedparcelable.ParcelField;
 import androidx.versionedparcelable.VersionedParcelize;
 
+import java.util.List;
+
 /**
  * Wire format for {@link
  * androidx.wear.watchface.style.ComplicationsUserStyleSetting.ComplicationsOption}.
@@ -50,10 +52,13 @@
      */
     @ParcelField(100)
     @NonNull
-    public ComplicationOverlayWireFormat[]
-            mComplicationOverlays =
+    public ComplicationOverlayWireFormat[] mComplicationOverlays =
             new ComplicationOverlayWireFormat[0];
 
+    @ParcelField(value = 101, defaultValue = "null")
+    @Nullable
+    public List<PerComplicationTypeMargins> mComplicationOverlaysMargins;
+
     ComplicationsOptionWireFormat() {
     }
 
@@ -61,6 +66,22 @@
             @NonNull byte[] id,
             @NonNull CharSequence displayName,
             @Nullable Icon icon,
+            @NonNull ComplicationOverlayWireFormat[] complicationOverlays,
+            @Nullable List<PerComplicationTypeMargins> complicationOverlaysMargins
+    ) {
+        super(id);
+        mDisplayName = displayName;
+        mIcon = icon;
+        mComplicationOverlays = complicationOverlays;
+        mComplicationOverlaysMargins = complicationOverlaysMargins;
+    }
+
+    /** @deprecated Use a constructor with perComplicationTypeMargins instead. */
+    @Deprecated
+    public ComplicationsOptionWireFormat(
+            @NonNull byte[] id,
+            @NonNull CharSequence displayName,
+            @Nullable Icon icon,
             @NonNull ComplicationOverlayWireFormat[]
                     complicationOverlays
     ) {
diff --git a/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/style/data/PerComplicationTypeMargins.java b/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/style/data/PerComplicationTypeMargins.java
new file mode 100644
index 0000000..372dd4a
--- /dev/null
+++ b/wear/watchface/watchface-data/src/main/java/androidx/wear/watchface/style/data/PerComplicationTypeMargins.java
@@ -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.wear.watchface.style.data;
+
+import android.graphics.RectF;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.versionedparcelable.ParcelField;
+import androidx.versionedparcelable.VersionedParcelable;
+import androidx.versionedparcelable.VersionedParcelize;
+
+import java.util.Map;
+
+/** @hide */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@VersionedParcelize
+public class PerComplicationTypeMargins implements VersionedParcelable {
+    @ParcelField(1)
+    @NonNull
+    public Map<Integer, RectF> mPerComplicationTypeMargins;
+
+    PerComplicationTypeMargins() {
+    }
+
+    public PerComplicationTypeMargins(
+            @NonNull Map<Integer, RectF> perComplicationTypeMargins
+    ) {
+        mPerComplicationTypeMargins = perComplicationTypeMargins;
+    }
+}
diff --git a/wear/watchface/watchface-guava/src/androidTest/java/androidx/wear/watchface/WatchFaceControlTestService.kt b/wear/watchface/watchface-guava/src/androidTest/java/androidx/wear/watchface/WatchFaceControlTestService.kt
index 9cdf97c..e437dc6 100644
--- a/wear/watchface/watchface-guava/src/androidTest/java/androidx/wear/watchface/WatchFaceControlTestService.kt
+++ b/wear/watchface/watchface-guava/src/androidTest/java/androidx/wear/watchface/WatchFaceControlTestService.kt
@@ -64,7 +64,7 @@
     private val realService = object : WatchFaceControlService() {
         override fun createServiceStub(): IWatchFaceInstanceServiceStub =
             object : IWatchFaceInstanceServiceStub(
-                ApplicationProvider.getApplicationContext<Context>(),
+                this@WatchFaceControlTestService,
                 MainScope()
             ) {
                 @RequiresApi(Build.VERSION_CODES.O_MR1)
diff --git a/wear/watchface/watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleSetting.kt b/wear/watchface/watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleSetting.kt
index 0e5ca1d..fcaac4e 100644
--- a/wear/watchface/watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleSetting.kt
+++ b/wear/watchface/watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleSetting.kt
@@ -22,6 +22,7 @@
 import android.content.res.Resources
 import android.content.res.XmlResourceParser
 import android.graphics.BitmapFactory
+import android.graphics.RectF
 import android.graphics.drawable.Icon
 import android.os.Build
 import android.os.Bundle
@@ -53,6 +54,7 @@
 import androidx.wear.watchface.style.data.LongRangeOptionWireFormat
 import androidx.wear.watchface.style.data.LongRangeUserStyleSettingWireFormat
 import androidx.wear.watchface.style.data.OptionWireFormat
+import androidx.wear.watchface.style.data.PerComplicationTypeMargins
 import androidx.wear.watchface.style.data.UserStyleSettingWireFormat
 import java.io.DataOutputStream
 import org.xmlpull.v1.XmlPullParser
@@ -963,7 +965,8 @@
             }
 
             internal constructor(
-                wireFormat: ComplicationOverlayWireFormat
+                wireFormat: ComplicationOverlayWireFormat,
+                perComplicationTypeMargins: Map<Int, RectF>?
             ) : this(
                 wireFormat.mComplicationSlotId,
                 when (wireFormat.mEnabled) {
@@ -979,8 +982,8 @@
                         perComplicationTypeBounds.mapKeys {
                             ComplicationType.fromWireType(it.key)
                         },
-                        wireFormat.mPerComplicationTypeMargins?.let { perComplicationTypeMargins ->
-                            perComplicationTypeMargins.mapKeys {
+                        perComplicationTypeMargins?.let { margins ->
+                            margins.mapKeys {
                                 ComplicationType.fromWireType(it.key)
                             }
                         } ?: emptyMap()
@@ -1008,10 +1011,7 @@
                     complicationSlotBounds?.perComplicationTypeBounds?.mapKeys {
                         it.key.toWireComplicationType()
                     },
-                    accessibilityTraversalIndex,
-                    complicationSlotBounds?.perComplicationTypeMargins?.mapKeys {
-                        it.key.toWireComplicationType()
-                    },
+                    accessibilityTraversalIndex
                 )
 
             internal companion object {
@@ -1354,7 +1354,13 @@
                 wireFormat: ComplicationsOptionWireFormat
             ) : super(Id(wireFormat.mId), emptyList()) {
                 complicationSlotOverlays =
-                    wireFormat.mComplicationOverlays.map { ComplicationSlotOverlay(it) }
+                    wireFormat.mComplicationOverlays.mapIndexed { index, value ->
+                        ComplicationSlotOverlay(
+                            value,
+                            wireFormat.mComplicationOverlaysMargins?.get(index)
+                                ?.mPerComplicationTypeMargins
+                        )
+                    }
                 displayNameInternal = DisplayText.CharSequenceDisplayText(wireFormat.mDisplayName)
                 icon = wireFormat.mIcon
                 watchFaceEditorData = null // This will get overwritten.
@@ -1396,7 +1402,15 @@
                     id.value,
                     displayName,
                     icon,
-                    complicationSlotOverlays.map { it.toWireFormat() }.toTypedArray()
+                    complicationSlotOverlays.map { it.toWireFormat() }.toTypedArray(),
+                    complicationSlotOverlays.map { overlay ->
+                        PerComplicationTypeMargins(
+                            overlay.complicationSlotBounds
+                                ?.perComplicationTypeMargins?.mapKeys {
+                                    it.key.toWireComplicationType()
+                                } ?: emptyMap()
+                        )
+                    }
                 )
 
             override fun write(dos: DataOutputStream) {
diff --git a/wear/watchface/watchface-style/src/test/java/androidx/wear/watchface/style/StyleParcelableTest.kt b/wear/watchface/watchface-style/src/test/java/androidx/wear/watchface/style/StyleParcelableTest.kt
index 561e104..666a11c 100644
--- a/wear/watchface/watchface-style/src/test/java/androidx/wear/watchface/style/StyleParcelableTest.kt
+++ b/wear/watchface/watchface-style/src/test/java/androidx/wear/watchface/style/StyleParcelableTest.kt
@@ -16,10 +16,12 @@
 
 package androidx.wear.watchface.style
 
+import android.graphics.RectF
 import android.graphics.drawable.Icon
 import android.os.Build
 import android.os.Parcel
 import androidx.annotation.RequiresApi
+import androidx.wear.watchface.complications.ComplicationSlotBounds
 
 import androidx.wear.watchface.style.UserStyleSetting.BooleanUserStyleSetting
 import androidx.wear.watchface.style.UserStyleSetting.ComplicationSlotsUserStyleSetting
@@ -595,6 +597,20 @@
                             enabled = false
                         )
                     )
+                ),
+                ComplicationSlotsUserStyleSetting.ComplicationSlotsOption(
+                    Option.Id("RIGHT_COMPLICATION_MOVED"),
+                    "MoveRight",
+                    null,
+                    listOf(
+                        ComplicationSlotsUserStyleSetting.ComplicationSlotOverlay(
+                            leftComplicationID,
+                            complicationSlotBounds = ComplicationSlotBounds(
+                                RectF(0.1f, 0.2f, 0.3f, 0.4f),
+                                RectF(0.5f, 0.6f, 0.7f, 0.8f)
+                            )
+                        )
+                    )
                 )
             ),
             listOf(WatchFaceLayer.COMPLICATIONS)
@@ -616,7 +632,7 @@
 
         val options = unparceled.options.filterIsInstance<
             ComplicationSlotsUserStyleSetting.ComplicationSlotsOption>()
-        assertThat(options.size).isEqualTo(4)
+        assertThat(options.size).isEqualTo(5)
         assertThat(options[0].id.value.decodeToString()).isEqualTo("LEFT_AND_RIGHT_COMPLICATIONS")
         assertThat(options[0].complicationSlotOverlays.size).isEqualTo(0)
 
@@ -639,6 +655,21 @@
         val options3Overlays = ArrayList(options[3].complicationSlotOverlays)
         assertThat(options3Overlays[0].complicationSlotId).isEqualTo(leftComplicationID)
         assertFalse(options3Overlays[0].enabled!!)
+
+        assertThat(options[4].id.value.decodeToString()).isEqualTo("RIGHT_COMPLICATION_MOVED")
+        assertThat(options[4].complicationSlotOverlays.size).isEqualTo(1)
+        val options4Overlays = ArrayList(options[4].complicationSlotOverlays)
+        assertThat(options4Overlays[0].complicationSlotId).isEqualTo(leftComplicationID)
+        assertThat(options4Overlays[0].enabled).isNull()
+
+        val expectedComplicationSlotBounds = ComplicationSlotBounds(
+            RectF(0.1f, 0.2f, 0.3f, 0.4f),
+            RectF(0.5f, 0.6f, 0.7f, 0.8f)
+        )
+        assertThat(options4Overlays[0].complicationSlotBounds?.perComplicationTypeBounds)
+            .containsExactlyEntriesIn(expectedComplicationSlotBounds.perComplicationTypeBounds)
+        assertThat(options4Overlays[0].complicationSlotBounds?.perComplicationTypeMargins)
+            .containsExactlyEntriesIn(expectedComplicationSlotBounds.perComplicationTypeMargins)
     }
 
     @Test
diff --git a/wear/watchface/watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleSettingTest.kt b/wear/watchface/watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleSettingTest.kt
index d8a617d..718ffa9 100644
--- a/wear/watchface/watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleSettingTest.kt
+++ b/wear/watchface/watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleSettingTest.kt
@@ -343,15 +343,17 @@
                 ComplicationType.LONG_TEXT.toWireComplicationType() to
                     RectF(0.5f, 0.6f, 0.7f, 0.8f)
             ),
-            null,
-            mapOf(
-                ComplicationType.LONG_TEXT.toWireComplicationType() to
-                    RectF(0.2f, 0.2f, 0.2f, 0.2f)
-           )
+            null
         )
 
         val overlay =
-            UserStyleSetting.ComplicationSlotsUserStyleSetting.ComplicationSlotOverlay(wireFormat)
+            UserStyleSetting.ComplicationSlotsUserStyleSetting.ComplicationSlotOverlay(
+                wireFormat,
+                mapOf(
+                    ComplicationType.LONG_TEXT.toWireComplicationType() to
+                        RectF(0.2f, 0.2f, 0.2f, 0.2f)
+                )
+            )
         val bounds = overlay.complicationSlotBounds!!.perComplicationTypeBounds
 
         // SHORT_TEXT and LONG_TEXT should match the input bounds
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 2d7842a..0b03632 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
@@ -432,7 +432,9 @@
      */
     @WorkerThread
     protected open fun createUserStyleSchema(): UserStyleSchema =
-        xmlSchemaAndComplicationSlotsDefinition.schema ?: UserStyleSchema(emptyList())
+        UserStyleSchema(
+            xmlSchemaAndComplicationSlotsDefinition.schema?.userStyleSettings ?: emptyList()
+        )
 
     /**
      * If the WatchFaceService's manifest doesn't define a
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/WatchFaceControlService.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/WatchFaceControlService.kt
index e158332..7c9524f 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/WatchFaceControlService.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/WatchFaceControlService.kt
@@ -16,6 +16,7 @@
 
 package androidx.wear.watchface.control
 
+import android.annotation.SuppressLint
 import android.app.Service
 import android.content.ComponentName
 import android.content.Context
@@ -99,7 +100,7 @@
 @RequiresApi(27)
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public open class IWatchFaceInstanceServiceStub(
-    private val context: Context,
+    private val service: Service,
     private val uiThreadCoroutineScope: CoroutineScope
 ) : IWatchFaceControlService.Stub() {
     override fun getApiVersion(): Int = IWatchFaceControlService.API_VERSION
@@ -119,7 +120,7 @@
     ): IHeadlessWatchFace? = TraceEvent(
         "IWatchFaceInstanceServiceStub.createHeadlessWatchFaceInstance"
     ).use {
-        createServiceAndHeadlessEngine(params.watchFaceName, context)?.let { serviceAndEngine ->
+        createServiceAndHeadlessEngine(params.watchFaceName)?.let { serviceAndEngine ->
             // This is serviced on a background thread so it should be fine to block.
             uiThreadCoroutineScope.runBlockingWithTracing("createHeadlessInstance") {
                 // However the WatchFaceService.createWatchFace method needs to be run on the UI
@@ -132,11 +133,25 @@
     private class ServiceAndEngine(
         val service: WatchFaceService,
         val engine: WatchFaceService.EngineWrapper
-    )
+    ) {
+        fun destroy() {
+            try {
+                engine.onDestroy()
+                service.onDestroy()
+            } catch (e: Exception) {
+                Log.e(
+                    TAG,
+                    "ServiceAndEngine.destroy failed due to exception",
+                    e
+                )
+                throw e
+            }
+        }
+    }
 
+    @SuppressLint("BanUncheckedReflection")
     private fun createServiceAndHeadlessEngine(
-        watchFaceName: ComponentName,
-        context: Context
+        watchFaceName: ComponentName
     ) = TraceEvent("IWatchFaceInstanceServiceStub.createEngine").use {
         // Attempt to construct the class for the specified watchFaceName, failing if it either
         // doesn't exist or isn't a [WatchFaceService].
@@ -147,7 +162,29 @@
             } else {
                 val watchFaceService =
                     watchFaceServiceClass.getConstructor().newInstance() as WatchFaceService
-                watchFaceService.setContext(context)
+
+                // Set the context and if possible the application for watchFaceService.
+                try {
+                    val method = Service::class.java.declaredMethods.find { it.name == "attach" }
+                    method!!.isAccessible = true
+                    method.invoke(
+                        watchFaceService,
+                        service as Context,
+                        null,
+                        watchFaceService::class.qualifiedName,
+                        null,
+                        service.application,
+                        null
+                    )
+                } catch (e: Exception) {
+                    Log.w(
+                        TAG,
+                        "createServiceAndHeadlessEngine can't call attach by reflection, " +
+                            "falling back to setContext",
+                        e
+                    )
+                    watchFaceService.setContext(watchFaceService)
+                }
                 watchFaceService.onCreate()
                 val engine =
                     watchFaceService.createHeadlessEngine() as WatchFaceService.EngineWrapper
@@ -192,103 +229,50 @@
 
     override fun getDefaultProviderPolicies(
         params: DefaultProviderPoliciesParams
-    ): Array<IdTypeAndDefaultProviderPolicyWireFormat>? = TraceEvent(
+    ): Array<IdTypeAndDefaultProviderPolicyWireFormat>? = createServiceAndHeadlessEngineAndEvaluate(
+        params.watchFaceName,
         "IWatchFaceInstanceServiceStub.getDefaultProviderPolicies"
-    ).use {
-        createServiceAndHeadlessEngine(params.watchFaceName, context)?.let { serviceAndEngine ->
-            try {
-                serviceAndEngine.engine.getDefaultProviderPolicies()
-            } catch (e: Exception) {
-                Log.e(TAG, "getDefaultProviderPolicies failed due to exception", e)
-                throw e
-            } finally {
-                try {
-                    serviceAndEngine.engine.onDestroy()
-                    serviceAndEngine.service.onDestroy()
-                } catch (e: Exception) {
-                    Log.e(
-                        TAG,
-                        "WatchfaceService.EngineWrapper.onDestroy failed due to exception",
-                        e
-                    )
-                    throw e
-                }
-            }
-        }
-    }
+    ) { it.engine.getDefaultProviderPolicies() }
 
     override fun getUserStyleSchema(
         params: GetUserStyleSchemaParams
-    ): UserStyleSchemaWireFormat? = TraceEvent(
+    ): UserStyleSchemaWireFormat? = createServiceAndHeadlessEngineAndEvaluate(
+        params.watchFaceName,
         "IWatchFaceInstanceServiceStub.getUserStyleSchema"
-    ).use {
-        createServiceAndHeadlessEngine(params.watchFaceName, context)?.let { serviceAndEngine ->
-            try {
-                serviceAndEngine.engine.getUserStyleSchemaWireFormat()
-            } catch (e: Exception) {
-                Log.e(TAG, "getUserStyleSchema failed due to exception", e)
-                throw e
-            } finally {
-                try {
-                    serviceAndEngine.engine.onDestroy()
-                    serviceAndEngine.service.onDestroy()
-                } catch (e: Exception) {
-                    Log.e(
-                        TAG,
-                        "WatchfaceService.EngineWrapper.onDestroy failed due to exception",
-                        e
-                    )
-                    throw e
-                }
-            }
-        }
-    }
+    ) { it.engine.getUserStyleSchemaWireFormat() }
 
     override fun getComplicationSlotMetadata(
         params: GetComplicationSlotMetadataParams
-    ): Array<ComplicationSlotMetadataWireFormat>? = TraceEvent(
+    ): Array<ComplicationSlotMetadataWireFormat>? = createServiceAndHeadlessEngineAndEvaluate(
+        params.watchFaceName,
         "IWatchFaceInstanceServiceStub.getComplicationSlotMetadata"
-    ).use {
-        createServiceAndHeadlessEngine(params.watchFaceName, context)?.let { serviceAndEngine ->
-            val result: Array<ComplicationSlotMetadataWireFormat>?
-            try {
-                result = serviceAndEngine.engine.getComplicationSlotMetadataWireFormats()
-            } catch (e: Exception) {
-                Log.e(TAG, "getComplicationSlotMetadata failed due to exception", e)
-                throw e
-            }
-            serviceAndEngine.engine.onDestroy()
-            serviceAndEngine.service.onDestroy()
-            result
-        }
-    }
+    ) { it.engine.getComplicationSlotMetadataWireFormats() }
 
     override fun hasComplicationCache() = true
 
     override fun getUserStyleFlavors(
         params: GetUserStyleFlavorsParams
-    ): UserStyleFlavorsWireFormat? = TraceEvent(
+    ): UserStyleFlavorsWireFormat? = createServiceAndHeadlessEngineAndEvaluate(
+        params.watchFaceName,
         "IWatchFaceInstanceServiceStub.getUserStyleFlavors"
-    ).use {
-        createServiceAndHeadlessEngine(params.watchFaceName, context)?.let { serviceAndEngine ->
-            try {
-                serviceAndEngine.engine.getUserStyleFlavorsWireFormat()
-            } catch (e: Exception) {
-                Log.e(TAG, "getUserStyleFlavors failed due to exception", e)
-                throw e
-            } finally {
+    ) { it.engine.getUserStyleFlavorsWireFormat() }
+
+    private fun <T> createServiceAndHeadlessEngineAndEvaluate(
+        watchFaceName: ComponentName,
+        functionName: String,
+        function: (serviceAndEngine: ServiceAndEngine) -> T
+    ): T? = TraceEvent(functionName).use {
+        return try {
+            createServiceAndHeadlessEngine(watchFaceName)?.let { serviceAndEngine ->
                 try {
-                    serviceAndEngine.engine.onDestroy()
-                    serviceAndEngine.service.onDestroy()
-                } catch (e: Exception) {
-                    Log.e(
-                        TAG,
-                        "WatchfaceService.EngineWrapper.onDestroy failed due to exception",
-                        e
-                    )
-                    throw e
+                    function(serviceAndEngine)
+                } finally {
+                    serviceAndEngine.destroy()
                 }
             }
+        } catch (e: Exception) {
+            Log.e(TAG, "$functionName failed due to exception", e)
+            throw e
         }
     }
 }
\ No newline at end of file
diff --git a/work/work-runtime/api/current.txt b/work/work-runtime/api/current.txt
index cca8486..a344bce 100644
--- a/work/work-runtime/api/current.txt
+++ b/work/work-runtime/api/current.txt
@@ -20,6 +20,7 @@
     method public int getMaxJobSchedulerId();
     method public int getMinJobSchedulerId();
     method public androidx.work.RunnableScheduler getRunnableScheduler();
+    method public androidx.work.SchedulingExceptionHandler? getSchedulingExceptionHandler();
     method public java.util.concurrent.Executor getTaskExecutor();
     method public androidx.work.WorkerFactory getWorkerFactory();
     field public static final int MIN_SCHEDULER_LIMIT = 20; // 0x14
@@ -35,6 +36,7 @@
     method public androidx.work.Configuration.Builder setMaxSchedulerLimit(int);
     method public androidx.work.Configuration.Builder setMinimumLoggingLevel(int);
     method public androidx.work.Configuration.Builder setRunnableScheduler(androidx.work.RunnableScheduler);
+    method public androidx.work.Configuration.Builder setSchedulingExceptionHandler(androidx.work.SchedulingExceptionHandler);
     method public androidx.work.Configuration.Builder setTaskExecutor(java.util.concurrent.Executor);
     method public androidx.work.Configuration.Builder setWorkerFactory(androidx.work.WorkerFactory);
   }
@@ -299,6 +301,10 @@
     method public void scheduleWithDelay(@IntRange(from=0) long, Runnable);
   }
 
+  public interface SchedulingExceptionHandler {
+    method public void handleException(Throwable);
+  }
+
   public abstract class WorkContinuation {
     ctor public WorkContinuation();
     method public static androidx.work.WorkContinuation combine(java.util.List<androidx.work.WorkContinuation!>);
diff --git a/work/work-runtime/api/public_plus_experimental_current.txt b/work/work-runtime/api/public_plus_experimental_current.txt
index cca8486..a344bce 100644
--- a/work/work-runtime/api/public_plus_experimental_current.txt
+++ b/work/work-runtime/api/public_plus_experimental_current.txt
@@ -20,6 +20,7 @@
     method public int getMaxJobSchedulerId();
     method public int getMinJobSchedulerId();
     method public androidx.work.RunnableScheduler getRunnableScheduler();
+    method public androidx.work.SchedulingExceptionHandler? getSchedulingExceptionHandler();
     method public java.util.concurrent.Executor getTaskExecutor();
     method public androidx.work.WorkerFactory getWorkerFactory();
     field public static final int MIN_SCHEDULER_LIMIT = 20; // 0x14
@@ -35,6 +36,7 @@
     method public androidx.work.Configuration.Builder setMaxSchedulerLimit(int);
     method public androidx.work.Configuration.Builder setMinimumLoggingLevel(int);
     method public androidx.work.Configuration.Builder setRunnableScheduler(androidx.work.RunnableScheduler);
+    method public androidx.work.Configuration.Builder setSchedulingExceptionHandler(androidx.work.SchedulingExceptionHandler);
     method public androidx.work.Configuration.Builder setTaskExecutor(java.util.concurrent.Executor);
     method public androidx.work.Configuration.Builder setWorkerFactory(androidx.work.WorkerFactory);
   }
@@ -299,6 +301,10 @@
     method public void scheduleWithDelay(@IntRange(from=0) long, Runnable);
   }
 
+  public interface SchedulingExceptionHandler {
+    method public void handleException(Throwable);
+  }
+
   public abstract class WorkContinuation {
     ctor public WorkContinuation();
     method public static androidx.work.WorkContinuation combine(java.util.List<androidx.work.WorkContinuation!>);
diff --git a/work/work-runtime/api/restricted_current.txt b/work/work-runtime/api/restricted_current.txt
index cca8486..a344bce 100644
--- a/work/work-runtime/api/restricted_current.txt
+++ b/work/work-runtime/api/restricted_current.txt
@@ -20,6 +20,7 @@
     method public int getMaxJobSchedulerId();
     method public int getMinJobSchedulerId();
     method public androidx.work.RunnableScheduler getRunnableScheduler();
+    method public androidx.work.SchedulingExceptionHandler? getSchedulingExceptionHandler();
     method public java.util.concurrent.Executor getTaskExecutor();
     method public androidx.work.WorkerFactory getWorkerFactory();
     field public static final int MIN_SCHEDULER_LIMIT = 20; // 0x14
@@ -35,6 +36,7 @@
     method public androidx.work.Configuration.Builder setMaxSchedulerLimit(int);
     method public androidx.work.Configuration.Builder setMinimumLoggingLevel(int);
     method public androidx.work.Configuration.Builder setRunnableScheduler(androidx.work.RunnableScheduler);
+    method public androidx.work.Configuration.Builder setSchedulingExceptionHandler(androidx.work.SchedulingExceptionHandler);
     method public androidx.work.Configuration.Builder setTaskExecutor(java.util.concurrent.Executor);
     method public androidx.work.Configuration.Builder setWorkerFactory(androidx.work.WorkerFactory);
   }
@@ -299,6 +301,10 @@
     method public void scheduleWithDelay(@IntRange(from=0) long, Runnable);
   }
 
+  public interface SchedulingExceptionHandler {
+    method public void handleException(Throwable);
+  }
+
   public abstract class WorkContinuation {
     ctor public WorkContinuation();
     method public static androidx.work.WorkContinuation combine(java.util.List<androidx.work.WorkContinuation!>);
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobSchedulerTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobSchedulerTest.java
index 9ba881f..9deafb2 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobSchedulerTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobSchedulerTest.java
@@ -49,6 +49,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.work.Configuration;
 import androidx.work.OneTimeWorkRequest;
+import androidx.work.SchedulingExceptionHandler;
 import androidx.work.WorkInfo;
 import androidx.work.WorkManagerTest;
 import androidx.work.impl.WorkDatabase;
@@ -236,6 +237,27 @@
     }
 
     @Test
+    @MediumTest
+    @SdkSuppress(minSdkVersion = 23)
+    public void testSchedulingExceptionHandler() {
+        doCallRealMethod().when(mSystemJobScheduler)
+                .scheduleInternal(any(WorkSpec.class), anyInt());
+
+        SchedulingExceptionHandler handler = mock(SchedulingExceptionHandler.class);
+        Configuration configuration = new Configuration.Builder()
+                .setSchedulingExceptionHandler(handler)
+                .build();
+
+        when(mWorkManager.getConfiguration()).thenReturn(configuration);
+        doThrow(new IllegalStateException("Error scheduling")).when(mJobScheduler).schedule(any());
+        OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
+        WorkSpec workSpec = work.getWorkSpec();
+        addToWorkSpecDao(workSpec);
+        mSystemJobScheduler.schedule(workSpec);
+        verify(handler, times(1)).handleException(any());
+    }
+
+    @Test
     @LargeTest
     @SdkSuppress(minSdkVersion = 23)
     public void testSystemJobScheduler_cancelsInvalidJobs() {
diff --git a/work/work-runtime/src/main/java/androidx/work/Configuration.java b/work/work-runtime/src/main/java/androidx/work/Configuration.java
index ad7605f..2867fb8 100644
--- a/work/work-runtime/src/main/java/androidx/work/Configuration.java
+++ b/work/work-runtime/src/main/java/androidx/work/Configuration.java
@@ -68,6 +68,8 @@
     @SuppressWarnings("WeakerAccess")
     final @Nullable InitializationExceptionHandler mExceptionHandler;
     @SuppressWarnings("WeakerAccess")
+    final @Nullable SchedulingExceptionHandler mSchedulingExceptionHandler;
+    @SuppressWarnings("WeakerAccess")
     final @Nullable String mDefaultProcessName;
     @SuppressWarnings("WeakerAccess")
     final int mLoggingLevel;
@@ -120,6 +122,7 @@
         mMaxJobSchedulerId = builder.mMaxJobSchedulerId;
         mMaxSchedulerLimit = builder.mMaxSchedulerLimit;
         mExceptionHandler = builder.mExceptionHandler;
+        mSchedulingExceptionHandler = builder.mSchedulingExceptionHandler;
         mDefaultProcessName = builder.mDefaultProcessName;
     }
 
@@ -253,10 +256,19 @@
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @Nullable
-    public InitializationExceptionHandler getExceptionHandler() {
+    public InitializationExceptionHandler getInitializationExceptionHandler() {
         return mExceptionHandler;
     }
 
+    /**
+     * @return the {@link SchedulingExceptionHandler} that can be used to intercept exceptions
+     * caused when trying to schedule {@link WorkRequest}s.
+     */
+    @Nullable
+    public SchedulingExceptionHandler getSchedulingExceptionHandler() {
+        return mSchedulingExceptionHandler;
+    }
+
     private @NonNull Executor createDefaultExecutor(boolean isTaskExecutor) {
         return Executors.newFixedThreadPool(
                 // This value is the same as the core pool size for AsyncTask#THREAD_POOL_EXECUTOR.
@@ -289,6 +301,7 @@
         Executor mTaskExecutor;
         RunnableScheduler mRunnableScheduler;
         @Nullable InitializationExceptionHandler mExceptionHandler;
+        @Nullable SchedulingExceptionHandler mSchedulingExceptionHandler;
         @Nullable String mDefaultProcessName;
 
         int mLoggingLevel;
@@ -327,6 +340,7 @@
             mMaxSchedulerLimit = configuration.mMaxSchedulerLimit;
             mRunnableScheduler = configuration.mRunnableScheduler;
             mExceptionHandler = configuration.mExceptionHandler;
+            mSchedulingExceptionHandler = configuration.mSchedulingExceptionHandler;
             mDefaultProcessName = configuration.mDefaultProcessName;
         }
 
@@ -489,6 +503,20 @@
         }
 
         /**
+         * Specifies the {@link SchedulingExceptionHandler} that can be used to intercept
+         * exceptions caused when trying to schedule {@link WorkRequest}s.
+         *
+         * @param schedulingExceptionHandler The {@link SchedulingExceptionHandler} instance
+         * @return This {@link Builder} instance
+         */
+        @NonNull
+        public Builder setSchedulingExceptionHandler(
+                @NonNull SchedulingExceptionHandler schedulingExceptionHandler) {
+            mSchedulingExceptionHandler = schedulingExceptionHandler;
+            return this;
+        }
+
+        /**
          * Designates the primary process that {@link WorkManager} should schedule work in.
          *
          * @param processName The {@link String} process name.
diff --git a/work/work-runtime/src/main/java/androidx/work/SchedulingExceptionHandler.java b/work/work-runtime/src/main/java/androidx/work/SchedulingExceptionHandler.java
new file mode 100644
index 0000000..7c0d8d2
--- /dev/null
+++ b/work/work-runtime/src/main/java/androidx/work/SchedulingExceptionHandler.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package androidx.work;
+
+import androidx.annotation.NonNull;
+
+/**
+ * An Exception Handler that can be used to determine if there were issues when trying
+ * to schedule {@link WorkRequest}s.
+ * <p>
+ * This typically happens when the application exceeds its scheduling limits because it is using a
+ * {@link  android.app.job.JobService} besides the one provided by {@link WorkManager}.
+ */
+public interface SchedulingExceptionHandler {
+    /**
+     * Allows the application to handle a {@link Throwable} throwable typically caused when
+     * trying to schedule {@link WorkRequest}s.
+     * <p>
+     * This exception handler will be invoked a thread bound to
+     * {@link Configuration#getTaskExecutor()}.
+     *
+     * @param throwable The underlying throwable that was caused when trying to schedule
+     *                  {@link WorkRequest}s.
+     */
+    void handleException(@NonNull Throwable throwable);
+}
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 1201feb..d0f1479 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
@@ -120,7 +120,7 @@
                 () -> mWorkDatabase.workSpecDao().getWorkSpec(id.getWorkSpecId())
         );
         if (workSpec == null) {
-            Logger.get().error(TAG, "Didn't find WorkSpec for id " + id);
+            Logger.get().warning(TAG, "Didn't find WorkSpec for id " + id);
             runOnExecuted(id, false);
             return false;
         }
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java b/work/work-runtime/src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java
index 1cdd29f..a999ffc 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/background/systemjob/SystemJobScheduler.java
@@ -37,6 +37,7 @@
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
 import androidx.work.Logger;
+import androidx.work.SchedulingExceptionHandler;
 import androidx.work.WorkInfo;
 import androidx.work.impl.Scheduler;
 import androidx.work.impl.WorkDatabase;
@@ -73,7 +74,8 @@
         this(context,
                 workManager,
                 (JobScheduler) context.getSystemService(JOB_SCHEDULER_SERVICE),
-                new SystemJobInfoConverter(context));
+                new SystemJobInfoConverter(context)
+        );
     }
 
     @VisibleForTesting
@@ -215,8 +217,18 @@
 
             Logger.get().error(TAG, message);
 
-            // Rethrow a more verbose exception.
-            throw new IllegalStateException(message, e);
+            IllegalStateException schedulingException = new IllegalStateException(message, e);
+            // If a SchedulingExceptionHandler is defined, let the app handle the scheduling
+            // exception.
+            SchedulingExceptionHandler handler =
+                    mWorkManager.getConfiguration().getSchedulingExceptionHandler();
+            if (handler != null) {
+                handler.handleException(schedulingException);
+            } else {
+                // Rethrow a more verbose exception.
+                throw schedulingException;
+            }
+
         } catch (Throwable throwable) {
             // OEM implementation bugs in JobScheduler cause the app to crash. Avoid crashing.
             Logger.get().error(TAG, "Unable to schedule " + workSpec, throwable);
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java b/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
index c81a331..805b8ee 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
+++ b/work/work-runtime/src/main/java/androidx/work/impl/utils/ForceStopRunnable.java
@@ -129,7 +129,7 @@
                         IllegalStateException throwable = new IllegalStateException(message,
                                 exception);
                         InitializationExceptionHandler exceptionHandler =
-                                mWorkManager.getConfiguration().getExceptionHandler();
+                                mWorkManager.getConfiguration().getInitializationExceptionHandler();
                         if (exceptionHandler != null) {
                             Logger.get().debug(TAG,
                                     "Routing exception to the specified exception handler",